]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/server/mutators/gamemode_keepaway.qc
Merge remote branch 'origin/master' into samual/keepaway
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / mutators / gamemode_keepaway.qc
1 void ka_SpawnBall(void);
2 void ka_TouchEvent(entity);
3 void ka_RespawnBall(void);
4
5 void ka_Initialize()
6 {
7         if(!g_keepaway)
8                 return;
9                 
10         precache_sound("keepaway/pickedup.wav");
11         precache_sound("keepaway/dropped.wav");
12         
13         entity e;
14         e = spawn();
15         e.think = ka_SpawnBall;
16         e.nextthink = time;
17 }
18
19 void ka_SpawnBall()
20 {
21         if(!g_keepaway) { 
22                 remove(self); 
23                 return; 
24         }
25         if (!self.model) {
26                 self.model = "models/nexball/ball.md3"; 
27                 self.scale = 1.3;
28         }
29
30         precache_model(self.model);
31         setmodel(self, self.model);
32         setsize(self, BALL_MINS, BALL_MAXS);
33         ball_scale = self.scale;
34         self.classname = "keepawayball";
35         self.damageforcescale = cvar("g_keepawayball_damageforcescale");
36         self.effects = self.effects | EF_FULLBRIGHT;
37         self.movetype = MOVETYPE_BOUNCE;
38         self.touch = ka_TouchEvent;
39         self.think = ka_RespawnBall;
40         self.nextthink = time;
41         self.flags = FL_ITEM;
42         //self.reset = ka_Reset;
43         self.owner = world;
44         
45         // todo: Waypoints and radar
46         //WaypointSprite_AttachCarrier();
47 }
48
49 void ka_RespawnBall()
50 {
51         if(MoveToRandomMapLocation(self, DPCONTENTS_SOLID | DPCONTENTS_CORPSE | DPCONTENTS_PLAYERCLIP, DPCONTENTS_SLIME | DPCONTENTS_LAVA | DPCONTENTS_SKY | DPCONTENTS_BODY | DPCONTENTS_DONOTENTER, Q3SURFACEFLAG_SKY, 10, 1024, 256))
52         {
53                 makevectors(self.angles);
54                 self.movetype = MOVETYPE_BOUNCE;
55                 self.velocity = '0 0 200';
56                 self.angles = '0 0 0';
57                 self.solid = SOLID_TRIGGER;
58                 //self.touch = ka_TouchEvent;
59                 self.think = ka_RespawnBall;
60                 self.nextthink = time + cvar("g_keepawayball_respawntime");
61         }
62         else
63         {
64                 // sorry, can't spawn, better luck next frame
65                 self.think = ka_RespawnBall;
66                 self.nextthink = time;
67         }
68 }
69
70 void ka_TouchEvent(entity plyr)
71 {
72         if(trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)
73         {
74                 self.think = ka_SpawnBall;
75                 self.nextthink = time;
76                 return;
77         }
78         if (!plyr) 
79                 return;
80         if (!self) 
81                 return;
82         if ((other.classname != "player" || other.health < 1) && (time > self.ctf_droptime + cvar("g_keepawayball_respawntime")))
83                 return;
84         if (self.wait > time)
85                 return;
86
87         self.owner = other;
88         other.ballcarried = self;
89         setattachment(self, other, "");
90         setorigin(self, BALL_ATTACHORG);
91         
92         self.velocity = '0 0 0';
93         self.movetype = MOVETYPE_NONE;
94         self.touch = SUB_Null;
95         self.alpha = 0.01;
96         
97         self.think = SUB_Null;
98         self.nextthink = 0;
99
100         self.glow_color = cvar("g_keepawayball_trail_color");
101         self.glow_trail = TRUE;
102         plyr.effects |= 8;
103         plyr.alpha = 0.6;
104
105         bprint(other.netname, "^7 has picked up the ball!\n");
106         WriteByte(MSG_BROADCAST, SVC_CENTERPRINT);
107         WriteString(MSG_BROADCAST, strcat("\n\n", other.netname, "^7 has picked up the ball!\n"));
108         sound(self.owner, CHAN_AUTO, "keepaway/pickedup.wav", VOL_BASE, ATTN_NORM);
109         
110         PlayerScore_Add(other, SP_KEEPAWAY_PICKUPS, 1);
111
112         // todo: Waypoints and radar
113 }
114
115 MUTATOR_HOOKFUNCTION(ka_RemovePlayer)
116 {
117         entity ball;
118         ball = self.ballcarried;
119
120         setattachment(ball, world, "");
121         ball.movetype = MOVETYPE_BOUNCE;
122         ball.solid = SOLID_TRIGGER;
123         ball.wait = time + 1;
124         ball.ctf_droptime = time;
125         ball.think = ka_SpawnBall;
126         ball.nextthink = time + cvar("g_keepawayball_respawntime");
127         ball.touch = ka_TouchEvent;
128         self.effects = EF_LOWPRECISION;
129         self.alpha = 1.0;
130         ball.alpha = 1.0;
131         setorigin(ball, self.origin + '0 0 10');
132         ball.velocity = '0 0 200' + '0 100 0'*crandom() + '100 0 0'*crandom();
133         
134         bprint(self.netname, "^7 has dropped the ball!\n");
135         WriteByte(MSG_BROADCAST, SVC_CENTERPRINT);
136         WriteString(MSG_BROADCAST, strcat("\n\n", self.netname, "^7 has dropped the ball!\n"));
137         sound(other, CHAN_AUTO, "keepaway/dropped.wav", VOL_BASE, ATTN_NORM);   
138         
139         PlayerScore_Add(self, SP_KEEPAWAY_DROPS, 1);
140         
141         // todo
142         //WaypointSprite_AttachCarrier("ka-ball", ball);
143         //WaypointSprite_Kill(plyr.waypointsprite_attachedforcarrier);
144         
145         ball.owner.ballcarried = world;
146         ball.owner = world;
147
148         return 1;
149 }
150
151 /*
152 void ka_DropEvent(entity plyr, entity ball)
153 {       
154         setattachment(ball, world, "");
155         ball.movetype = MOVETYPE_BOUNCE;
156         ball.solid = SOLID_TRIGGER;
157         ball.wait = time + 1;
158         ball.ctf_droptime = time;
159         ball.think = ka_SpawnBall;
160         ball.nextthink = time + cvar("g_keepawayball_respawntime");
161         ball.touch = ka_TouchEvent;
162         plyr.effects = EF_LOWPRECISION;
163         plyr.alpha = 1.0;
164         ball.alpha = 1.0;
165         setorigin(ball, plyr.origin + '0 0 10');
166         ball.velocity = '0 0 200' + '0 100 0'*crandom() + '100 0 0'*crandom();
167         
168         bprint(plyr.netname, "^7 has dropped the ball!\n");
169         WriteByte(MSG_BROADCAST, SVC_CENTERPRINT);
170         WriteString(MSG_BROADCAST, strcat("\n\n", plyr.netname, "^7 has dropped the ball!\n"));
171         sound(other, CHAN_AUTO, "keepaway/dropped.wav", VOL_BASE, ATTN_NORM);   
172         
173         PlayerScore_Add(plyr, SP_KEEPAWAY_DROPS, 1);
174         
175         // todo
176         //WaypointSprite_AttachCarrier("ka-ball", ball);
177         //WaypointSprite_Kill(plyr.waypointsprite_attachedforcarrier);
178         
179         ball.owner.kaballcarried = world;
180         ball.owner = world;
181 }
182
183
184 void ka_CheckWinner()
185 {
186
187 }
188
189 MUTATOR_HOOKFUNCTION(ka_PlayerDies)
190 {
191         float i;
192         entity e;
193
194         float temp_tag_players_count;
195         temp_tag_players_count = tag_players_count;
196
197         if(frag_target.tagcolor == frag_target.tagcolor_original) // if this is the first time we die... (our tagcolor remained unchanged)
198         {
199                 for(i = 0; i < temp_tag_players_count; ++i) // check other players...
200                 {
201                         e = tag_players[i];
202                         if(e == world) // empty slot, skip to next
203                         {
204                                 if(temp_tag_players_count < TAGCOLOR_MAX - 1) // just in case
205                                         ++temp_tag_players_count;
206                                 continue;
207                         }
208
209                         if(e.tagcolor == frag_target.tagcolor_original) // and see if they have our original tag color
210                         {
211                                 tag_GetFragAttackers_ColorOwner();
212                                 centerprint(e, strcat("^1Your master ^7", frag_target.netname, "^1 was tagged by ^7", frag_attacker.netname, " ^1with ^7", color_owner_red, " ^1color.\n"));
213                                 e.tagcolor = frag_attacker.tagcolor; // if so, remove it, our tag color has now "died out" from this round and we can not win anymore. The attacker will "summon" all of our previously fragged targets, and also us.
214                                 setcolor(e, 16 * e.tagcolor + e.tagcolor);
215                         }
216                 }
217         }
218         else
219         {
220                 frag_target.tagcolor = frag_attacker.tagcolor;
221                 setcolor(frag_target, 16 * frag_target.tagcolor + frag_target.tagcolor);
222         }
223
224         tag_GetFragAttackers_ColorOwner();
225
226         if(color_owner_self)
227                 color_owner_green = "^2your own";
228         centerprint(frag_attacker, strcat("^2You tagged ^7", frag_target.netname, " ^2with ^7", color_owner_green, " ^2color.\n"));
229
230         if(color_owner_self)
231                 color_owner_red = "^1their own";
232         centerprint(frag_target, strcat("^1You were tagged by ^7", frag_attacker.netname, " ^1with ^7", color_owner_red, " ^1color.\n"));
233         bprint("^7", frag_target.netname, "^1 was tagged by ^7", frag_attacker.netname, " ^1with ^7", color_owner_red, " ^1color.\n");
234
235         frag_target.health = cvar("g_balance_health_start"); // "respawn" the player :P
236
237         tag_CheckWinner();
238
239         return 1;
240 }
241
242 MUTATOR_HOOKFUNCTION(tag_RemovePlayer)
243 {
244
245         return 1;
246 }
247
248 MUTATOR_HOOKFUNCTION(tag_GiveFragsForKill)
249 {
250         frag_score = 0; // no frags counted in Tag, maybe later (TODO)
251         return 1;
252 }
253
254 MUTATOR_HOOKFUNCTION(tag_PlayerPreThink)
255 {
256         setcolor(self, 16 * self.tagcolor + self.tagcolor); // prevent cheating by changing player colors
257         return 1;
258 }
259 */
260
261
262 MUTATOR_DEFINITION(gamemode_keepaway)
263 {
264         MUTATOR_HOOK(MakePlayerObserver, ka_RemovePlayer, CBC_ORDER_ANY);
265         MUTATOR_HOOK(ClientDisconnect, ka_RemovePlayer, CBC_ORDER_ANY);
266         //MUTATOR_HOOK(PlayerDies, ka_PlayerDies, CBC_ORDER_ANY);
267         //MUTATOR_HOOK(PlayerSpawn, ka_PlayerSpawn, CBC_ORDER_ANY);
268         //MUTATOR_HOOK(GiveFragsForKill, ka_GiveFragsForKill, CBC_ORDER_FIRST);
269         //MUTATOR_HOOK(PlayerPreThink, ka_PlayerPreThink, CBC_ORDER_FIRST);
270
271         MUTATOR_ONADD
272         {
273                 if(time > 1) // game loads at time 1
274                         error("This is a game type and it cannot be added at runtime.");
275                 g_keepaway = 1;
276                 ka_Initialize();
277         }
278
279         MUTATOR_ONREMOVE
280         {
281                 g_keepaway = 0;
282                 error("This is a game type and it cannot be removed at runtime.");
283         }
284
285         return 0;
286 }
287