]> icculus.org git repositories - divverent/nexuiz.git/blob - data/qcsrc/server/assault.qc
do less audio spam for triggers that don't even respond to players
[divverent/nexuiz.git] / data / qcsrc / server / assault.qc
1 void spawnfunc_func_breakable();
2 void target_objective_decrease_activate();
3 .entity assault_decreaser;
4 .entity assault_sprite;
5
6 void spawnfunc_info_player_attacker() {
7         if(!g_assault)
8         {
9                 remove(self);
10                 return;
11         }
12         self.team = COLOR_TEAM1; // red, gets swapped every round
13         spawnfunc_info_player_deathmatch();
14 }
15
16 void spawnfunc_info_player_defender() {
17         if(!g_assault)
18         {
19                 remove(self);
20                 return;
21         }
22         self.team = COLOR_TEAM2; // blue, gets swapped every round
23         spawnfunc_info_player_deathmatch();
24 }
25
26 // reset this objective. Used when spawning an objective
27 // and when a new round starts
28 void assault_objective_reset() {
29         self.health = ASSAULT_VALUE_INACTIVE;
30 }
31
32 void assault_objective_use() {
33         if(other.classname == "info_player_deathmatch") // a spawn, a spawn
34                 return;
35
36         // activate objective
37         self.health = 100;
38         //print("^2Activated objective ", self.targetname, "=", etos(self), "\n");
39         //print("Activator is ", activator.classname, "\n");
40
41         entity oldself;
42         oldself = self;
43
44         for(self = world; (self = find(self, target, oldself.targetname)); )
45         {
46                 if(self.classname == "target_objective_decrease")
47                         target_objective_decrease_activate();
48         }
49
50         self = oldself;
51 }
52
53 void spawnfunc_target_objective() {
54         self.classname = "target_objective";
55         self.use = assault_objective_use;
56         assault_objective_reset();
57 }
58
59
60 // decrease the health of targeted objectives
61 void assault_objective_decrease_use() {
62         if(activator.team != assault_attacker_team) {
63                 // wrong team triggered decrease
64                 return;
65         }
66
67         if(other.assault_sprite.classname == "assault_decreaser_sprite")
68                 WaypointSprite_Disown(other.assault_sprite, waypointsprite_deadlifetime);
69         else
70                 return; // already activated! cannot activate again!
71
72         if(self.enemy.health < ASSAULT_VALUE_INACTIVE)
73         {
74                 if(self.enemy.health - self.dmg > 0.5)
75                 {
76                         PlayerTeamScore_Add(activator, SP_SCORE, ST_SCORE, self.dmg);
77                         self.enemy.health = self.enemy.health - self.dmg;
78                 }
79                 else
80                 {
81                         PlayerTeamScore_Add(activator, SP_SCORE, ST_SCORE, self.enemy.health);
82                         PlayerTeamScore_Add(activator, SP_ASSAULT_OBJECTIVES, ST_ASSAULT_OBJECTIVES, 1);
83                         self.enemy.health = -1;
84
85                         entity oldself, oldactivator;
86
87                         oldself = self;
88                         self = oldself.enemy;
89                                 oldactivator = activator;
90                                 activator = oldself;
91                                         SUB_UseTargets();
92                                 activator = oldactivator;
93                         self = oldself;
94                 }
95         }
96 }
97
98 void assault_setenemytoobjective()
99 {
100         local entity objective;
101         for(objective = world; (objective = find(objective, targetname, self.target)); ) {
102                 if(objective.classname == "target_objective") {
103                         if(self.enemy == world)
104                                 self.enemy = objective;
105                         else
106                                 objerror("more than one objective as target - fix the map!");
107                         break;
108                 }
109         }
110
111         if(self.enemy == world)
112                 objerror("no objective as target - fix the map!");
113 }
114
115 float assault_decreaser_sprite_visible(entity e)
116 {
117         entity decreaser;
118
119         decreaser = self.assault_decreaser;
120
121         if(decreaser.enemy.health >= ASSAULT_VALUE_INACTIVE)
122                 return FALSE;
123
124         return TRUE;
125 }
126
127 void target_objective_decrease_activate()
128 {
129         entity ent, spr;
130         self.owner = world;
131         for(ent = world; (ent = find(ent, target, self.targetname)); )
132         {
133                 if(ent.assault_sprite != world)
134                         WaypointSprite_Disown(ent.assault_sprite, waypointsprite_deadlifetime);
135
136                 spr = WaypointSprite_SpawnFixed("<placeholder>", 0.5 * (ent.absmin + ent.absmax), ent, assault_sprite);
137                 spr.assault_decreaser = self;
138                 spr.waypointsprite_visible_for_player = assault_decreaser_sprite_visible;
139                 spr.classname = "assault_decreaser_sprite";
140                 WaypointSprite_UpdateRule(spr, assault_attacker_team, SPRITERULE_TEAMPLAY);
141                 if(ent.classname == "func_assault_destructible")
142                         WaypointSprite_UpdateSprites(spr, "as-defend", "as-destroy", "as-destroy");
143                 else
144                         WaypointSprite_UpdateSprites(spr, "as-defend", "as-push", "as-push");
145                 WaypointSprite_UpdateTeamRadar(spr, RADARICON_OBJECTIVE, '1 0.5 0');
146         }
147 }
148
149 void target_objective_decrease_findtarget()
150 {
151         assault_setenemytoobjective();
152 }
153
154 //=============================================================================
155
156 void spawnfunc_target_objective_decrease() {
157
158         self.classname = "target_objective_decrease";
159
160         if(!self.dmg) {
161                 self.dmg = 101;
162         }
163         self.use = assault_objective_decrease_use;
164         self.health = ASSAULT_VALUE_INACTIVE;
165         self.max_health = ASSAULT_VALUE_INACTIVE;
166         self.enemy = world;
167
168         InitializeEntity(self, target_objective_decrease_findtarget, INITPRIO_FINDTARGET);
169 }
170
171 // destructible walls that can be used to trigger target_objective_decrease
172 void spawnfunc_func_assault_destructible() {
173         self.spawnflags = 3;
174         spawnfunc_func_breakable();
175 }
176
177 void assault_wall_think() {
178         if(self.enemy.health < 0) {
179                 self.model = "";
180                 self.solid = SOLID_NOT;
181         } else {
182                 self.model = self.mdl;
183                 self.solid = SOLID_BSP;
184         }
185
186         self.nextthink = time + 0.2;
187 }
188
189 void spawnfunc_func_assault_wall() {
190         self.classname = "func_assault_wall";
191         self.mdl = self.model;
192         setmodel(self, self.mdl);
193         self.solid = SOLID_BSP;
194         self.think = assault_wall_think;
195         self.nextthink = time;
196         InitializeEntity(self, assault_setenemytoobjective, INITPRIO_FINDTARGET);
197 }
198
199
200 void target_assault_roundend_reset() {
201         //print("round end reset\n");
202         self.cnt = self.cnt + 1; // up round counter
203         self.winning = 0; // up round
204 }
205
206 void target_assault_roundend_use() {
207         self.winning = 1; // round has been won by attackers
208 }
209
210 void spawnfunc_target_assault_roundend() {
211         self.winning = 0; // round not yet won by attackers
212         self.classname = "target_assault_roundend";
213         self.use = target_assault_roundend_use;
214         self.cnt = 0; // first round
215 }
216
217 void assault_roundstart_use() {
218
219         activator = self;
220         SUB_UseTargets();
221
222         /*
223 #ifdef TTURRETS_ENABLED
224 entity ent,oldself;
225
226         //(Re)spawn all turrets
227         oldself = self;
228         ent = find(world, classname, "turret_main");
229         while(ent) {
230         // Swap turret teams
231         if(ent.team == COLOR_TEAM1)
232         ent.team = COLOR_TEAM2;
233         else
234         ent.team = COLOR_TEAM1;
235
236         self = ent;
237
238         // Dubbles as teamchange
239         turret_stdproc_respawn();
240         //ent.turret_spawnfunc();
241
242         ent = find(ent, classname, "turret_main");
243         }
244         self = oldself;
245 #endif
246 */
247
248 }
249
250 void spawnfunc_target_assault_roundstart() {
251         assault_attacker_team = COLOR_TEAM1;
252         self.classname = "target_assault_roundstart";
253         self.use = assault_roundstart_use;
254         InitializeEntity(self, assault_roundstart_use, INITPRIO_FINDTARGET);
255 }
256
257 // trigger new round
258 // reset objectives, toggle spawnpoints, reset triggers, ...
259 void assault_new_round() {
260         //bprint("ASSAULT: new round\n");
261
262         // up round counter
263         self.winning = self.winning + 1;
264
265         // swap attacker/defender roles
266         if(assault_attacker_team == COLOR_TEAM1) {
267                 assault_attacker_team = COLOR_TEAM2;
268         } else {
269                 assault_attacker_team = COLOR_TEAM1;
270         }
271
272         // swap spawn point teams
273         local entity ent;
274         ent = find(world, classname, "info_player_deathmatch");
275         while (ent)
276         {
277                 if(ent.team == COLOR_TEAM1) {
278                         ent.team = COLOR_TEAM2;
279                 } else {
280                         ent.team = COLOR_TEAM1;
281                 }
282                 ent = find(ent, classname, "info_player_deathmatch");
283         }
284
285         // swap all destructibles
286         ent = find(world, classname, "func_assault_destructible");
287         while (ent)
288         {
289                 if(ent.team == COLOR_TEAM1)
290                         ent.team = COLOR_TEAM2;
291                 else
292                         ent.team = COLOR_TEAM1;
293                 ent = find(ent, classname, "func_assault_destructible");
294         }
295
296         // reset the level with a countdown
297         cvar_set("timelimit", ftos(ceil(time - game_starttime) / 60));
298         ReadyRestartForce(); // sets game_starttime
299 }