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