]> icculus.org git repositories - divverent/nexuiz.git/blob - data/qcsrc/server/assault.qc
assault: (untested) make breakables show a radar wave when attacked
[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 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.sprite.classname == "assault_decreaser_sprite")
68                 WaypointSprite_Disown(other.sprite, waypointsprite_deadlifetime);
69
70         if(self.enemy.health < ASSAULT_VALUE_INACTIVE)
71         {
72                 if(self.enemy.health - self.dmg > 0.5)
73                 {
74                         PlayerTeamScore_Add(activator, SP_SCORE, ST_SCORE, self.dmg);
75                         self.enemy.health = self.enemy.health - self.dmg;
76                 }
77                 else
78                 {
79                         PlayerTeamScore_Add(activator, SP_SCORE, ST_SCORE, self.enemy.health);
80                         PlayerTeamScore_Add(activator, SP_ASSAULT_OBJECTIVES, ST_ASSAULT_OBJECTIVES, 1);
81                         self.enemy.health = -1;
82
83                         entity oldself, oldactivator;
84
85                         oldself = self;
86                         self = oldself.enemy;
87                                 oldactivator = activator;
88                                 activator = oldself;
89                                         SUB_UseTargets();
90                                 activator = oldactivator;
91                         self = oldself;
92                 }
93         }
94 }
95
96 void assault_setenemytoobjective()
97 {
98         local entity objective;
99         for(objective = world; (objective = find(objective, targetname, self.target)); ) {
100                 if(objective.classname == "target_objective") {
101                         if(self.enemy == world)
102                                 self.enemy = objective;
103                         else
104                                 objerror("more than one objective as target - fix the map!");
105                         break;
106                 }
107         }
108
109         if(self.enemy == world)
110                 objerror("no objective as target - fix the map!");
111 }
112
113 float assault_decreaser_sprite_visible(entity e)
114 {
115         entity decreaser;
116         entity object;
117
118         decreaser = self.assault_decreaser;
119
120         if(decreaser.enemy.health >= ASSAULT_VALUE_INACTIVE)
121                 return FALSE;
122
123         return TRUE;
124 }
125
126 void target_objective_decrease_activate()
127 {
128         entity ent, spr;
129         self.owner = world;
130         for(ent = world; (ent = find(ent, target, self.targetname)); )
131         {
132                 if(ent.sprite != world)
133                         WaypointSprite_Disown(ent.sprite, waypointsprite_deadlifetime);
134
135                 spr = WaypointSprite_SpawnFixed("<placeholder>", 0.5 * (ent.absmin + ent.absmax), ent, sprite);
136                 spr.assault_decreaser = self;
137                 spr.waypointsprite_visible_for_player = assault_decreaser_sprite_visible;
138                 spr.classname = "assault_decreaser_sprite";
139                 WaypointSprite_UpdateRule(spr, assault_attacker_team, SPRITERULE_TEAMPLAY);
140                 if(ent.classname == "func_assault_destructible")
141                         WaypointSprite_UpdateSprites(spr, "as-defend", "as-destroy", "as-destroy");
142                 else
143                         WaypointSprite_UpdateSprites(spr, "as-defend", "as-push", "as-push");
144                 WaypointSprite_UpdateTeamRadar(spr, RADARICON_OBJECTIVE, '1 0.5 0');
145         }
146 }
147
148 void target_objective_decrease_findtarget()
149 {
150         assault_setenemytoobjective();
151 }
152
153 //=============================================================================
154
155 void spawnfunc_target_objective_decrease() {
156
157         self.classname = "target_objective_decrease";
158
159         precache_model("models/sprites/defend.sp2");
160         precache_model("models/sprites/destroy.sp2");
161         precache_model("models/sprites/push.sp2");
162
163         if(!self.dmg) {
164                 self.dmg = 101;
165         }
166         self.use = assault_objective_decrease_use;
167         self.health = ASSAULT_VALUE_INACTIVE;
168         self.max_health = ASSAULT_VALUE_INACTIVE;
169         self.enemy = world;
170
171         InitializeEntity(self, target_objective_decrease_findtarget, INITPRIO_FINDTARGET);
172 }
173
174 // destructible walls that can be used to trigger target_objective_decrease
175 void spawnfunc_func_assault_destructible() {
176         self.spawnflags = 3;
177         spawnfunc_func_breakable();
178 }
179
180 void assault_wall_think() {
181         if(self.enemy.health < 0) {
182                 self.model = "";
183                 self.solid = SOLID_NOT;
184         } else {
185                 self.model = self.mdl;
186                 self.solid = SOLID_BSP;
187         }
188
189         self.nextthink = time + 0.2;
190 }
191
192 void spawnfunc_func_assault_wall() {
193         self.classname = "func_assault_wall";
194         self.mdl = self.model;
195         setmodel(self, self.mdl);
196         self.solid = SOLID_BSP;
197         self.think = assault_wall_think;
198         self.nextthink = time;
199         InitializeEntity(self, assault_setenemytoobjective, INITPRIO_FINDTARGET);
200 }
201
202
203 void target_assault_roundend_reset() {
204         self.cnt = self.cnt + 1; // up round counter
205         self.winning = 0; // up round
206 }
207
208 void target_assault_roundend_use() {
209         self.winning = 1; // round has been won by attackers
210 }
211
212 void spawnfunc_target_assault_roundend() {
213         if(!self.health)
214                 self.health = 300; // 5 minutes
215
216         cvar_set("timelimit", ftos(self.health/60));
217         self.winning = 0; // round not yet won by attackers
218         self.classname = "target_assault_roundend";
219         self.use = target_assault_roundend_use;
220         self.cnt = 0; // first round
221 }
222
223 void assault_roundstart_use() {
224
225         activator = self;
226         SUB_UseTargets();
227
228         /*
229 #ifdef TTURRETS_ENABLED
230 entity ent,oldself;
231
232         //(Re)spawn all turrets
233         oldself = self;
234         ent = find(world, classname, "turret_main");
235         while(ent) {
236         // Swap turret teams
237         if(ent.team == COLOR_TEAM1)
238         ent.team = COLOR_TEAM2;
239         else
240         ent.team = COLOR_TEAM1;
241
242         self = ent;
243
244         // Dubbles as teamchange
245         turret_stdproc_respawn();
246         //ent.turret_spawnfunc();
247
248         ent = find(ent, classname, "turret_main");
249         }
250         self = oldself;
251 #endif
252 */
253
254 }
255
256 void spawnfunc_target_assault_roundstart() {
257         assault_attacker_team = COLOR_TEAM1;
258         self.classname = "target_assault_roundstart";
259         self.use = assault_roundstart_use;
260         InitializeEntity(self, assault_roundstart_use, INITPRIO_FINDTARGET);
261 }
262
263 // trigger new round
264 // reset objectives, toggle spawnpoints, reset triggers, ...
265 void assault_new_round() {
266         bprint("ASSAULT: new round\n");
267
268         // up round counter
269         self.winning = self.winning + 1;
270         // set end time for next round
271         self.cnt = time + self.health;
272
273         // swap attacker/defender roles
274         if(assault_attacker_team == COLOR_TEAM1) {
275                 assault_attacker_team = COLOR_TEAM2;
276         } else {
277                 assault_attacker_team = COLOR_TEAM1;
278         }
279
280         // swap spawn point teams
281         local entity ent;
282         local entity oldself;
283         ent = find(world, classname, "info_player_deathmatch");
284         while (ent)
285         {
286                 if(ent.team == COLOR_TEAM1) {
287                         ent.team = COLOR_TEAM2;
288                 } else {
289                         ent.team = COLOR_TEAM1;
290                 }
291                 ent = find(ent, classname, "info_player_deathmatch");
292         }
293
294         // swap all destructibles
295         ent = find(world, classname, "func_assault_destructible");
296         while (ent)
297         {
298                 if(ent.team == COLOR_TEAM1)
299                         ent.team = COLOR_TEAM2;
300                 else
301                         ent.team = COLOR_TEAM1;
302                 ent = find(ent, classname, "func_assault_destructible");
303         }
304
305         // reset the level with a countdown
306         cvar_set("timelimit", ftos(ceil(time - game_starttime) / 60));
307         ReadyRestartForce(); // sets game_starttime
308 }