]> 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(void);
3 void ka_RespawnBall(void);
4 void ka_DropEvent(entity);
5 void ka_UpdateState(entity);
6
7 void ka_Initialize()
8 {
9         if(!g_keepaway)
10                 return;
11                 
12         precache_sound("keepaway/pickedup.wav");
13         precache_sound("keepaway/dropped.wav");
14
15         ScoreRules_keepaway();
16         
17         entity e;
18         e = spawn();
19         e.think = ka_SpawnBall;
20         e.nextthink = time;
21 }
22
23 void ka_SpawnBall() // self = the ball
24 {
25         if(!g_keepaway) { 
26                 remove(self); 
27                 return; 
28         }
29         if (!self.model) {
30                 self.model = "models/orbs/orbblue.md3"; 
31                 self.scale = 1;
32         }
33
34         precache_model(self.model);
35         setmodel(self, self.model);
36         setsize(self, BALL_MINS, BALL_MAXS);
37         ball_scale = self.scale;
38         self.classname = "keepawayball";
39         self.damageforcescale = cvar("g_keepawayball_damageforcescale");
40         self.takedamage = DAMAGE_YES;
41         self.effects = self.effects | EF_FULLBRIGHT;
42         self.movetype = MOVETYPE_BOUNCE;
43         self.touch = ka_TouchEvent;
44         self.think = ka_RespawnBall;
45         self.nextthink = time;
46         self.flags = FL_ITEM;
47         //self.reset = ka_Reset;
48         self.owner = world;
49         
50         //WaypointSprite_AttachCarrier("ka-ball", self);
51         WaypointSprite_Spawn("ka-ball", 0, 0, self, '0 0 64', world, self.team, self, waypointsprite_attachedforcarrier, FALSE);
52         WaypointSprite_UpdateTeamRadar(self.waypointsprite_attachedforcarrier, RADARICON_FLAGCARRIER, '0 1 1');
53         // wtf radar doesn't work when not in a team environment?
54 }
55
56 void ka_RespawnBall()
57 {
58         if(MoveToRandomMapLocation(self, DPCONTENTS_SOLID | DPCONTENTS_CORPSE | DPCONTENTS_PLAYERCLIP, DPCONTENTS_SLIME | DPCONTENTS_LAVA | DPCONTENTS_SKY | DPCONTENTS_BODY | DPCONTENTS_DONOTENTER, Q3SURFACEFLAG_SKY, 10, 1024, 256))
59         {
60                 makevectors(self.angles);
61                 self.movetype = MOVETYPE_BOUNCE;
62                 self.velocity = '0 0 200';
63                 self.angles = '0 0 0';
64                 self.solid = SOLID_TRIGGER;
65                 //self.touch = ka_TouchEvent;
66                 self.think = ka_RespawnBall;
67                 self.nextthink = time + cvar("g_keepawayball_respawntime");
68         }
69         else
70         {
71                 // sorry, can't spawn, better luck next frame
72                 self.think = ka_RespawnBall;
73                 self.nextthink = time;
74         }
75 }
76
77 void ka_TouchEvent()
78 {
79         if(trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)
80         {
81                 self.think = ka_SpawnBall;
82                 self.nextthink = time;
83                 return;
84         }
85         if(other.classname != "player" || other.health < 1) { return; }
86         if(!self) { return; }
87         if(self.wait > time) { return; }
88
89         self.owner = other;
90         other.kaballcarried = self;
91         setattachment(self, other, "");
92         setorigin(self, BALL_ATTACHORG);
93         
94         self.velocity = '0 0 0';
95         self.movetype = MOVETYPE_NONE;
96         self.touch = SUB_Null;
97         self.alpha = 0.01;
98         self.think = SUB_Null;
99         self.nextthink = 0;
100         self.glow_color = cvar("g_keepawayball_trail_color");
101         self.glow_trail = TRUE;
102         self.takedamage = DAMAGE_NO;
103
104         other.effects |= 8;
105         other.alpha = 0.6;
106
107         ka_UpdateState(other);
108
109         bprint(other.netname, "^7 has picked up the ball!\n");
110         if(other.items & IT_KEY1) { bprint(other.netname, "^7 has the ball in their inventory.\n"); }
111         WriteByte(MSG_BROADCAST, SVC_CENTERPRINT);
112         WriteString(MSG_BROADCAST, strcat("\n\n", other.netname, "^7 has picked up the ball!\n"));
113         sound(self.owner, CHAN_AUTO, "keepaway/pickedup.wav", VOL_BASE, ATTN_NONE);
114         
115         PlayerScore_Add(other, SP_KEEPAWAY_PICKUPS, 1);
116
117         WaypointSprite_AttachCarrier("ka-ballcarrier", other);
118         WaypointSprite_UpdateRule(other.waypointsprite_attachedforcarrier, 0, SPRITERULE_DEFAULT);
119         WaypointSprite_UpdateTeamRadar(other.waypointsprite_attachedforcarrier, RADARICON_FLAGCARRIER, '1 0 0');
120         WaypointSprite_Ping(other.waypointsprite_attachedforcarrier);   
121         WaypointSprite_Kill(self.waypointsprite_attachedforcarrier);
122 }
123
124 void ka_DropEvent(entity plyr) 
125 {
126         entity ball;
127         ball = plyr.kaballcarried;
128
129         if(!ball) { return; }
130         
131         setattachment(ball, world, "");
132         ball.movetype = MOVETYPE_BOUNCE;
133         ball.solid = SOLID_TRIGGER;
134         ball.wait = time + 1; 
135         ball.think = ka_SpawnBall;
136         ball.nextthink = time + cvar("g_keepawayball_respawntime");
137         ball.touch = ka_TouchEvent;
138         ball.takedamage = DAMAGE_YES;
139         plyr.effects = EF_LOWPRECISION;
140         plyr.alpha = 1.0;
141         ball.alpha = 1.0;
142         setorigin(ball, plyr.origin + '0 0 10');
143         ball.velocity = '0 0 200' + '0 100 0'*crandom() + '100 0 0'*crandom();
144         ball.owner.kaballcarried = world;
145         ball.owner = world;
146         
147         ka_UpdateState(plyr);
148         
149         bprint(plyr.netname, "^7 has dropped the ball!\n");
150         if(plyr.items & IT_KEY1) { bprint(plyr.netname, "^7 has the ball in their inventory.\n"); }
151         WriteByte(MSG_BROADCAST, SVC_CENTERPRINT);
152         WriteString(MSG_BROADCAST, strcat("\n\n", plyr.netname, "^7 has dropped the ball!\n"));
153         sound(other, CHAN_AUTO, "keepaway/dropped.wav", VOL_BASE, ATTN_NONE);   
154         
155         PlayerScore_Add(plyr, SP_KEEPAWAY_DROPS, 1);
156         
157         WaypointSprite_Spawn("ka-ball", 0, 0, ball, '0 0 64', world, ball.team, ball, waypointsprite_attachedforcarrier, FALSE);
158         WaypointSprite_UpdateRule(ball.waypointsprite_attachedforcarrier, 0, SPRITERULE_DEFAULT);
159         WaypointSprite_UpdateTeamRadar(ball.waypointsprite_attachedforcarrier, RADARICON_FLAGCARRIER, '0 1 1');
160         WaypointSprite_Ping(ball.waypointsprite_attachedforcarrier);    
161         WaypointSprite_Kill(plyr.waypointsprite_attachedforcarrier);
162 }
163
164 void ka_UpdateState(entity plyr)
165 {
166         if(plyr.kaballcarried) {
167                 plyr.items |= IT_KEY1; 
168         }
169 }
170
171 MUTATOR_HOOKFUNCTION(ka_RemovePlayer)
172 {
173         if(self.kaballcarried) { ka_DropEvent(self); }
174         return 1;
175 }
176
177 MUTATOR_HOOKFUNCTION(ka_Scoring)
178 {
179         if((frag_attacker != frag_target) && (frag_attacker.classname == "player"))
180         {
181                 if(frag_target.kaballcarried) { // get amount of times killing carrier
182                         PlayerScore_Add(frag_attacker, SP_KEEPAWAY_CARRIERKILLS, 1);
183                         if(cvar("g_keepaway_bckillscore"))
184                                 PlayerScore_Add(frag_attacker, SP_KEEPAWAY_SCORE, 1);
185                 }
186                 else if(!frag_attacker.kaballcarried)
187                         if(cvar("g_keepaway_noncarrier_warn"))
188                                 centerprint_atprio(frag_attacker, (CENTERPRIO_SPAM + 5), "Killing people while you don't have the ball gives no points!");
189
190                 if(frag_attacker.kaballcarried) // get kills as carrier
191                         PlayerScore_Add(frag_attacker, SP_KEEPAWAY_SCORE, 1);
192         }
193
194         if(self.items & IT_KEY1) { bprint(self.netname, "^7 has the ball in their inventory.\n"); }
195
196         if(self.kaballcarried) { ka_DropEvent(self); }
197         return 1;
198 }
199
200 MUTATOR_HOOKFUNCTION(ka_GiveFragsForKill)
201 {
202         frag_score = 0; // no frags counted in keepaway
203         return 1;
204 }
205
206 MUTATOR_HOOKFUNCTION(ka_PlayerPreThink)
207 {
208         if(self.kaballcarried) {
209                 self.items |= IT_KEY1; 
210         }
211         //if(self.items & IT_KEY1) { bprint(self.netname, "^7 has the ball in their inventory.\n"); }
212         return 1;
213 }
214
215 //MUTATOR_HOOKFUNCTION(ka_SpectateCopy)
216 //{
217 //      self.items = other.items;
218 //      return 1;
219 //}
220
221 MUTATOR_DEFINITION(gamemode_keepaway)
222 {
223         MUTATOR_HOOK(MakePlayerObserver, ka_RemovePlayer, CBC_ORDER_ANY);
224         MUTATOR_HOOK(ClientDisconnect, ka_RemovePlayer, CBC_ORDER_ANY);
225         MUTATOR_HOOK(PlayerDies, ka_Scoring, CBC_ORDER_ANY);
226         MUTATOR_HOOK(GiveFragsForKill, ka_GiveFragsForKill, CBC_ORDER_FIRST);
227         MUTATOR_HOOK(PlayerPreThink, ka_PlayerPreThink, CBC_ORDER_FIRST);
228         //MUTATOR_HOOK(SpectateCopy, ka_SpectateCopy, CBC_ORDER_ANY);
229
230         MUTATOR_ONADD
231         {
232                 if(time > 1) // game loads at time 1
233                         error("This is a game type and it cannot be added at runtime.");
234                 g_keepaway = 1;
235                 ka_Initialize();
236         }
237
238         MUTATOR_ONREMOVE
239         {
240                 g_keepaway = 0;
241                 error("This is a game type and it cannot be removed at runtime.");
242         }
243
244         return 0;
245 }