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