]> icculus.org git repositories - divverent/nexuiz.git/blob - data/qcsrc/server/assault.qc
target2 handling improved
[divverent/nexuiz.git] / data / qcsrc / server / assault.qc
1 void spawnfunc_func_breakable();
2
3 //=============================================================================
4
5 /*QUAKED spawnfunc_info_player_attacker (1 0 0) (-16 -16 -24) (16 16 45) INITIAL
6 Normal attacker spawning location for Nexuiz Asssault
7 -------- KEYS --------
8 angle : direction in which player will look when spawning in the game. Does not apply to bots.
9 target : this should point to a spawnfunc_target_objective to decide when this spawning point is active.
10 nobots : when set to 1, bots will never use this spawn point to respawn in the game.
11 nohumans : when set to 1, human players will never use this spawn point to respawn in the game.
12 notfree : when set to 1, entity will not spawn in "Free for all" and "Tournament" modes.
13 notteam : when set to 1, entity will not spawn in "Teamplay" and "CTF" modes.
14 notsingle : when set to 1, entity will not spawn in Single Player mode (bot play mode).
15 -------- SPAWNFLAGS --------
16 INITIAL : makes the spawnpoint the initial place for the player to spawn at the beginning of the game.*/
17 void spawnfunc_info_player_attacker() {
18         self.team = COLOR_TEAM1; // red, gets swapped every round
19         spawnfunc_info_player_deathmatch();
20 }
21
22 //=============================================================================
23
24 /*QUAKED spawnfunc_info_player_defender (0 1 0) (-16 -16 -24) (16 16 45) INITIAL
25 Normal defender spawning location for Nexuiz Asssault
26 -------- KEYS --------
27 angle : direction in which player will look when spawning in the game. Does not apply to bots.
28 target : this should point to a spawnfunc_target_objective to decide when this spawning point is active.
29 nobots : when set to 1, bots will never use this spawn point to respawn in the game.
30 nohumans : when set to 1, human players will never use this spawn point to respawn in the game.
31 notfree : when set to 1, entity will not spawn in "Free for all" and "Tournament" modes.
32 notteam : when set to 1, entity will not spawn in "Teamplay" and "CTF" modes.
33 notsingle : when set to 1, entity will not spawn in Single Player mode (bot play mode).
34 -------- SPAWNFLAGS --------
35 INITIAL : makes the spawnpoint the initial place for the player to spawn at the beginning of the game.*/
36 void spawnfunc_info_player_defender() {
37         self.team = COLOR_TEAM2; // blue, gets swapped every round
38         spawnfunc_info_player_deathmatch();
39 }
40
41 // reset this objective. Used when spawning an objective
42 // and when a new round starts
43 void assault_objective_reset() {
44         self.health = ASSAULT_VALUE_INACTIVE;
45 }
46
47 void assault_objective_use() {
48         // activate objective
49         self.health = 100;
50         self.nextthink = time + 0.1;
51 }
52
53 void assault_objective_think() {
54         if(self.health < 0) {
55                 //self.effects = 0;
56                 activator = self;
57                 SUB_UseTargets();
58         } else {
59                 //self.effects = EF_STARDUST;
60                 self.nextthink = time + 0.1;
61         }
62
63 }
64 //=============================================================================
65
66 /*QUAKED spawnfunc_target_objective (0 .5 0) (-8 -8 -8) (8 8 8)
67 Objective controller for Nexuiz Assault. When active it has 100 health. If it falls below 0 then
68 it'll trigger the next targeted entity (usually the next objective or spawnfunc_target_assault_roundend etc.)
69 -------- KEYS --------
70 targetname : point to e.g. next objective*/
71 void spawnfunc_target_objective() {
72         self.classname = "target_objective";
73         self.think = assault_objective_think;
74         self.use = assault_objective_use;
75         assault_objective_reset();
76 }
77
78 float assault_objective_decrease_customizeforclient() {
79         if(!self.spawnflags)
80                 return FALSE;
81
82         if(self.cnt == 0) {
83                 if(other.team == assault_attacker_team)
84                         if(self.spawnflags == 1)
85                                 setmodel(self, "models/sprites/push.sp2");
86                         else
87                                 setmodel(self, "models/sprites/destroy.sp2");
88                 else
89                         setmodel(self, "models/sprites/defend.sp2");
90         } else {
91                 return FALSE;
92         }
93         return TRUE;
94 }
95
96
97 void assault_objective_decrease_think() {
98
99         local entity objective;
100         local float found;
101         found = 0;
102         objective = find(world, targetname, self.target);
103         while(objective && found == 0) {
104                 if(objective.classname == "target_objective") {
105                         found = 1;
106                         if(objective.health < ASSAULT_VALUE_INACTIVE) { // targeted objective is active
107                                 if(self.cnt == 1 && self.max_health >= ASSAULT_VALUE_INACTIVE) {
108                                         // decrease was fired already, but objective did recover (round reset)
109                                         self.cnt = 0;
110                                 }
111                         } else { // objective isn't active
112                                 self.cnt = 1;
113                         }
114                         self.max_health = objective.health; // save current objective status for next think
115                 }
116         }
117
118         if(!self.spawnflags) {
119                 local entity ent;
120                 ent = find(world, target, self.targetname);
121                 if(ent) {
122                         if(ent.classname == "func_assault_destructible")
123                                 self.spawnflags = 2;
124                         else
125                                 self.spawnflags = 1;
126                 }
127         }
128
129         self.nextthink = time + 0.2;
130 }
131
132
133 // decrease the health of targeted objectives
134 void assault_objective_decrease_use() {
135         if(other.classname == "info_player_deathmatch") // a spawn, a spawn
136                 return;
137
138         if(self.cnt > 0) {
139                 // did already fire
140                 return;
141         }
142
143         if(activator.team != assault_attacker_team) {
144                 // wrong team triggered decrease
145                 return;
146         }
147
148         local entity ent;
149         ent = find(world, targetname, self.target);
150         while(ent) {
151                 if(ent.health > 0 && ent.health < ASSAULT_VALUE_INACTIVE)
152                         ent.health = ent.health - self.dmg;
153                 ent = find(ent, targetname, self.target);
154         }
155
156         self.cnt = 1;
157 }
158
159 //=============================================================================
160
161 /*QUAKED target_objective_decrease (0 .5 0) (-8 -8 -8) (8 8 8)
162 When triggered decreases health of the targeted spawnfunc_target_objective.
163 -------- KEYS --------
164 targetname : point to a spawnfunc_target_objective entity*/
165 void spawnfunc_target_objective_decrease() {
166
167         self.classname = "target_objective_decrease";
168
169         precache_model("models/sprites/defend.sp2");
170         precache_model("models/sprites/destroy.sp2");
171         precache_model("models/sprites/push.sp2");
172
173         if(!self.dmg) {
174                 self.dmg = 101;
175         }
176         self.cnt = 0; // not used yet
177         self.use = assault_objective_decrease_use;
178         self.mdl = "models/sprites/here.sp2";
179         self.effects = EF_NODEPTHTEST;
180         self.health = ASSAULT_VALUE_INACTIVE;
181         self.max_health = ASSAULT_VALUE_INACTIVE;
182         self.think = assault_objective_decrease_think;
183         self.customizeentityforclient = assault_objective_decrease_customizeforclient;
184         self.nextthink = time;
185 }
186
187
188 void assault_destructible_reset() {
189         self.health = self.max_health;
190         self.model = self.mdl;
191         self.solid = SOLID_BSP;
192         self.colormod = '1 1 1';
193         self.cnt = 0; // not active
194         if(self.spawnflags)
195         {
196                 activator = self;
197                 self.use();
198         }
199 }
200
201 // destructible walls that can be used to trigger target_objective_decrease
202 void spawnfunc_func_assault_destructible() {
203         self.spawnflags = 3;
204         spawnfunc_func_breakable();
205 }
206
207 void assault_wall_think() {
208         local entity ent;
209         local float notvisible;
210         notvisible = 0;
211         ent = find(world, targetname, self.target);
212         while(ent) {
213                 if(ent.classname == "target_objective" && ent.health < 0)
214                         notvisible = 1;
215                 ent = find(ent, targetname, self.target);
216         }
217
218         if(notvisible) {
219                 self.model = "";
220                 self.solid = SOLID_NOT;
221         } else {
222                 self.model = self.mdl;
223                 self.solid = SOLID_BSP;
224         }
225
226         self.nextthink = time + 0.2;
227 }
228
229 void spawnfunc_func_assault_wall() {
230         self.classname = "func_assault_wall";
231         self.mdl = self.model;
232         setmodel(self, self.mdl);
233         self.solid = SOLID_BSP;
234         self.think = assault_wall_think;
235         self.nextthink = time;
236 }
237
238
239 void target_assault_roundend_reset() {
240         self.cnt = self.cnt + 1; // up round counter
241         self.winning = 0; // up round
242 }
243
244 void target_assault_roundend_use() {
245         self.winning = 1; // round has been won by attackers
246 }
247
248 void spawnfunc_target_assault_roundend() {
249         if(!self.health)
250                 self.health = 300; // 5 minutes
251
252         cvar_set("timelimit", ftos(self.health/60));
253         self.winning = 0; // round not yet won by attackers
254         self.classname = "target_assault_roundend";
255         self.use = target_assault_roundend_use;
256         self.cnt = 0; // first round
257 }
258
259 void assault_roundstart_use() {
260
261         activator = self;
262         SUB_UseTargets();
263
264 /*
265 #ifdef TTURRETS_ENABLED
266     entity ent,oldself;
267
268         //(Re)spawn all turrets
269         oldself = self;
270         ent = find(world, classname, "turret_main");
271         while(ent) {
272             // Swap turret teams
273         if(ent.team == COLOR_TEAM1)
274             ent.team = COLOR_TEAM2;
275         else
276             ent.team = COLOR_TEAM1;
277
278         self = ent;
279
280         // Dubbles as teamchange
281         turret_stdproc_respawn();
282         //ent.turret_spawnfunc();
283
284                 ent = find(ent, classname, "turret_main");
285         }
286         self = oldself;
287 #endif
288 */
289
290 }
291
292 void spawnfunc_target_assault_roundstart() {
293         assault_attacker_team = COLOR_TEAM1;
294         self.classname = "target_assault_roundstart";
295         self.use = assault_roundstart_use;
296         self.think = assault_roundstart_use;
297         self.nextthink = time + 0.1;
298 }
299
300 // trigger new round
301 // reset objectives, toggle spawnpoints, reset triggers, ...
302 void assault_new_round() {
303
304         // up round counter
305         self.winning = self.winning + 1;
306         // set end time for next round
307         self.cnt = time + self.health;
308
309         // swap spawn point teams
310         local entity ent;
311         local entity oldself;
312
313         // reward attackers for winning the round
314         ent = find(world, classname, "player");
315         while(ent) {
316                 if(ent.team == assault_attacker_team) {
317                         UpdateFrags(ent, 10);
318                 }
319                 ent = find(ent, classname, "player");
320         }
321
322         // swap attacker/defender roles
323         if(assault_attacker_team == COLOR_TEAM1) {
324                 assault_attacker_team = COLOR_TEAM2;
325         } else {
326                 assault_attacker_team = COLOR_TEAM1;
327         }
328
329         ent = find(world, classname, "info_player_deathmatch");
330         while (ent)
331         {
332                 oldself = self;
333                 self = ent;
334                 if(self.team == COLOR_TEAM1) {
335                         self.team = COLOR_TEAM2;
336                 } else {
337                         self.team = COLOR_TEAM1;
338                 }
339                 self = oldself;
340
341                 ent = find(ent, classname, "info_player_deathmatch");
342         }
343
344         // reset all objectives
345         ent = find(world, classname, "target_objective");
346         while (ent)
347         {
348                 oldself = self;
349                 self = ent;
350                 assault_objective_reset();
351                 self = oldself;
352
353                 ent = find(ent, classname, "target_objective");
354         }
355
356         // reset round end triggers
357         ent = find(world, classname, "target_assault_roundend");
358         while (ent)
359         {
360                 oldself = self;
361                 self = ent;
362                 target_assault_roundend_reset();
363                 self = oldself;
364
365                 ent = find(ent, classname, "target_assault_roundend");
366         }
367
368         // reset all target_object_decrease
369         ent = find(world, classname, "target_objective_decrease");
370         while (ent)
371         {
372                 ent.cnt = 0;
373                 ent = find(ent, classname, "target_objective_decrease");
374         }
375
376         // reset all spawnfunc_func_assault_destructible
377         ent = find(world, classname, "func_assault_destructible");
378         while (ent)
379         {
380                 oldself = self;
381                 self = ent;
382
383         if(ent.team == COLOR_TEAM1)
384             ent.team = COLOR_TEAM2;
385         else
386             ent.team = COLOR_TEAM1;
387
388                 assault_destructible_reset();
389                 self = oldself;
390                 ent = find(ent, classname, "func_assault_destructible");
391         }
392
393         ent = find(world, classname, "target_assault_roundstart");
394         while (ent)
395         {
396                 oldself = self;
397                 self = ent;
398                 self.use();
399                 self = oldself;
400                 ent = find(ent, classname, "target_assault_roundstart");
401         }
402
403         // actually restart round... how to do that?
404         ent = find(world, classname, "player");
405         while(ent) {
406                 oldself = self;
407                 self = ent;
408                 PutClientInServer();
409                 self = oldself;
410                 ent = find(ent, classname, "player");
411
412         }
413
414
415 }
416
417