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