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