Xonotic QuakeC
The free, fast arena FPS with crisp movement and a wide array of weapons
sv_cts.qc
Go to the documentation of this file.
1#include "sv_cts.qh"
2
3#include <server/client.qh>
4#include <server/race.qh>
5#include <server/world.qh>
6#include <server/gamelog.qh>
11
16
17// legacy bot roles
20{
21 if(IS_DEAD(this))
22 return;
23
25 {
27
28 bool raw_touch_check = true;
29 int cp = this.race_checkpoint;
30
31 LABEL(search_racecheckpoints)
33 {
34 if(it.cnt == cp || cp == -1)
35 {
36 // redirect bot to next goal if it touched the waypoint of an untouchable checkpoint
37 // e.g. checkpoint in front of Stormkeep's warpzone
38 // the same workaround is applied in Race gametype
39 if (raw_touch_check && vdist(this.origin - it.nearestwaypoint.origin, <, 30))
40 {
41 cp = race_NextCheckpoint(cp);
42 raw_touch_check = false;
43 goto search_racecheckpoints;
44 }
45 navigation_routerating(this, it, 1000000, 5000);
46 }
47 });
48
50
52 }
53}
54
56{
58 GameRules_scoring(0, 0, 0, {
60 field(SP_RACE_FASTEST, "fastest", SFL_SORT_PRIO_PRIMARY | SFL_LOWER_IS_BETTER | SFL_TIME);
61 } else {
62 field(SP_RACE_LAPS, "laps", SFL_SORT_PRIO_PRIMARY);
63 field(SP_RACE_TIME, "time", SFL_SORT_PRIO_SECONDARY | SFL_LOWER_IS_BETTER | SFL_TIME);
64 field(SP_RACE_FASTEST, "fastest", SFL_LOWER_IS_BETTER | SFL_TIME);
65 }
66 });
67}
68
69void cts_EventLog(string mode, entity actor) // use an alias for easy changing and quick editing later
70{
72 GameLogEcho(strcat(":cts:", mode, ":", ((actor != NULL) ? (strcat(":", ftos(actor.playerid))) : "")));
73}
74
75MUTATOR_HOOKFUNCTION(cts, PlayerPhysics)
76{
77 entity player = M_ARGV(0, entity);
78 float dt = M_ARGV(1, float);
79
80 player.race_movetime_frac += dt;
81 float f = floor(player.race_movetime_frac);
82 player.race_movetime_frac -= f;
83 player.race_movetime_count += f;
84 player.race_movetime = player.race_movetime_frac + player.race_movetime_count;
85
86 if(IS_PLAYER(player))
87 {
88 if (player.race_penalty)
89 if (time > player.race_penalty)
90 player.race_penalty = 0;
91 if(player.race_penalty)
92 {
93 player.velocity = '0 0 0';
95 player.disableclientprediction = 2;
96 }
97 }
98
99 // force kbd movement for fairness
100 float wishspeed;
101 vector wishvel;
102
103 // if record times matter
104 // ensure nothing EVIL is being done (i.e. div0_evade)
105 // this hinders joystick users though
106 // but it still gives SOME analog control
107 wishvel.x = fabs(CS(player).movement.x);
108 wishvel.y = fabs(CS(player).movement.y);
109 if(wishvel.x != 0 && wishvel.y != 0 && wishvel.x != wishvel.y)
110 {
111 wishvel.z = 0;
112 wishspeed = vlen(wishvel);
113 if(wishvel.x >= 2 * wishvel.y)
114 {
115 // pure X motion
116 if(CS(player).movement.x > 0)
117 CS(player).movement_x = wishspeed;
118 else
119 CS(player).movement_x = -wishspeed;
120 CS(player).movement_y = 0;
121 }
122 else if(wishvel.y >= 2 * wishvel.x)
123 {
124 // pure Y motion
125 CS(player).movement_x = 0;
126 if(CS(player).movement.y > 0)
127 CS(player).movement_y = wishspeed;
128 else
129 CS(player).movement_y = -wishspeed;
130 }
131 else
132 {
133 // diagonal
134 if(CS(player).movement.x > 0)
135 CS(player).movement_x = M_SQRT1_2 * wishspeed;
136 else
137 CS(player).movement_x = -M_SQRT1_2 * wishspeed;
138 if(CS(player).movement.y > 0)
139 CS(player).movement_y = M_SQRT1_2 * wishspeed;
140 else
141 CS(player).movement_y = -M_SQRT1_2 * wishspeed;
142 }
143 }
144}
145
146MUTATOR_HOOKFUNCTION(cts, reset_map_global)
147{
148 float s;
149
151
153 PlayerScore_Sort(race_place, 0, true, false);
154
155 FOREACH_CLIENT(true, {
156 if(it.race_place)
157 {
158 s = GameRules_scoring_add(it, RACE_FASTEST, 0);
159 if(!s)
160 it.race_place = 0;
161 }
162 cts_EventLog(ftos(it.race_place), it);
163 });
164
165 if(g_race_qualifying == 2)
166 {
169 cvar_set("fraglimit", ftos(race_fraglimit));
170 cvar_set("leadlimit", ftos(race_leadlimit));
171 cvar_set("timelimit", ftos(race_timelimit));
173 }
174}
175
177{
178 entity player = M_ARGV(0, entity);
179
180 race_PreparePlayer(player);
181 player.race_checkpoint = -1;
182
183 race_SendAll(player, false);
184}
185
186MUTATOR_HOOKFUNCTION(cts, AbortSpeedrun)
187{
188 entity player = M_ARGV(0, entity);
189
191 race_PreparePlayer(player); // nice try
192}
193
194MUTATOR_HOOKFUNCTION(cts, MakePlayerObserver)
195{
196 entity player = M_ARGV(0, entity);
197
198 if(GameRules_scoring_add(player, RACE_FASTEST, 0))
199 player.frags = FRAGS_PLAYER_OUT_OF_GAME;
200 else
201 player.frags = FRAGS_SPECTATOR;
202
203 race_PreparePlayer(player);
204 player.race_checkpoint = -1;
205}
206
207MUTATOR_HOOKFUNCTION(cts, PlayerSpawn)
208{
209 entity player = M_ARGV(0, entity);
210 entity spawn_spot = M_ARGV(1, entity);
211
212 if(spawn_spot.target == "")
213 // Emergency: this wasn't a real spawnpoint. Can this ever happen?
214 race_PreparePlayer(player);
215
216 // if we need to respawn, do it right
217 player.race_respawn_checkpoint = player.race_checkpoint;
218 player.race_respawn_spotref = spawn_spot;
219
220 player.race_place = 0;
221}
222
224{
225 entity player = M_ARGV(0, entity);
226
227 if(IS_PLAYER(player))
228 if(!game_stopped)
229 {
230 if(CS(player).killcount == FRAGS_SPECTATOR /* initial spawn */ || g_race_qualifying) // spawn
231 race_PreparePlayer(player);
232 else // respawn
233 race_RetractPlayer(player);
234
235 race_AbandonRaceCheck(player);
236 }
237}
238
239MUTATOR_HOOKFUNCTION(cts, PlayerDamaged)
240{
241 return true; // forbid logging damage
242}
243
244MUTATOR_HOOKFUNCTION(cts, PlayerDies)
245{
247
248 frag_target.respawn_flags |= RESPAWN_FORCE;
250
252 {
253 IL_EACH(g_projectiles, it.owner == frag_target && (it.flags & FL_PROJECTILE),
254 {
255 delete(it);
256 });
257 }
258}
259
260MUTATOR_HOOKFUNCTION(cts, HavocBot_ChooseRole)
261{
262 entity bot = M_ARGV(0, entity);
263
264 bot.havocbot_role = havocbot_role_cts;
265 return true;
266}
267
269{
270 entity player = M_ARGV(0, entity);
271
273 race_SpeedAwardFrame(player);
274}
275
276MUTATOR_HOOKFUNCTION(cts, ForbidThrowCurrentWeapon)
277{
278 // no weapon dropping in CTS
279 return true;
280}
281
282MUTATOR_HOOKFUNCTION(cts, FilterItem)
283{
284 entity item = M_ARGV(0, entity);
285
286 if (ITEM_IS_LOOT(item))
287 {
288 if(item.monster_item && autocvar_g_cts_drop_monster_items)
289 return false;
290 return true;
291 }
292}
293
294MUTATOR_HOOKFUNCTION(cts, MonsterDropItem)
295{
297 M_ARGV(1, string) = "";
298}
299
300MUTATOR_HOOKFUNCTION(cts, Damage_Calculate)
301{
302 entity frag_attacker = M_ARGV(1, entity);
304 float frag_deathtype = M_ARGV(3, float);
305 float frag_damage = M_ARGV(4, float);
306
307 if(frag_target == frag_attacker || frag_deathtype == DEATH_FALL.m_id)
309 {
310 frag_damage = 0;
311 M_ARGV(4, float) = frag_damage;
312 }
313}
314
315MUTATOR_HOOKFUNCTION(cts, ForbidPlayerScore_Clear)
316{
317 return true; // in CTS, you don't lose score by observing
318}
319
320MUTATOR_HOOKFUNCTION(cts, GetRecords)
321{
322 int record_page = M_ARGV(0, int);
323 string ret_string = M_ARGV(1, string);
324
325 for(int i = record_page * 200; i < MapInfo_count && i < record_page * 200 + 200; ++i)
326 {
327 if(MapInfo_Get_ByID(i))
328 {
330
331 if(!r)
332 continue;
333
334 string h = race_readName(MapInfo_Map_bspname, 1);
335 ret_string = strcat(ret_string, strpad(32, MapInfo_Map_bspname), " ", strpad(-8, TIME_ENCODED_TOSTRING(r, false)), " ", h, "\n");
336 }
337 }
338
339 M_ARGV(1, string) = ret_string;
340}
341
343{
344 M_ARGV(1, float) = 0; // kill delay
345}
346
347MUTATOR_HOOKFUNCTION(cts, Race_FinalCheckpoint)
348{
349 entity player = M_ARGV(0, entity);
350
351 // useful to prevent cheating by running back to the start line and starting out with more speed
354}
355
357{
358 entity player = M_ARGV(0, entity);
359
360 stuffcmd(player, "cl_cmd settemp cl_movecliptokeyboard 2\n");
361}
362
363MUTATOR_HOOKFUNCTION(cts, WantWeapon)
364{
365 M_ARGV(1, float) = (M_ARGV(0, entity) == WEP_SHOTGUN); // want weapon = weapon info
366 M_ARGV(3, bool) = true; // want mutator blocked
367 return true;
368}
369
370MUTATOR_HOOKFUNCTION(cts, ForbidDropCurrentWeapon)
371{
372 return true;
373}
374
void navigation_goalrating_start(entity this)
void navigation_goalrating_timeout_set(entity this)
Definition navigation.qc:20
bool navigation_goalrating_timeout(entity this)
Definition navigation.qc:44
void navigation_routerating(entity this, entity e, float f, float rangebias)
void navigation_goalrating_end(entity this)
#define MUTATOR_HOOKFUNCTION(...)
Definition base.qh:335
var entity(vector mins, vector maxs,.entity tofield) findbox_tofield_OrFallback
void ClientKill_Silent(entity this, float _delay)
#define M_ARGV(x, type)
Definition events.qh:17
vector movement
Definition player.qh:229
#define IS_DEAD(s)
Definition player.qh:245
#define IS_PLAYER(s)
Definition player.qh:243
const int SFL_LOWER_IS_BETTER
Lower scores are better (e.g.
Definition scores.qh:102
const int SFL_TIME
Display as mm:ss.s, value is stored as 10ths of a second (AND 0 is the worst possible value!...
Definition scores.qh:122
const int SFL_SORT_PRIO_SECONDARY
Scoring priority (NOTE: PRIMARY is used for fraglimit) NOTE: SFL_SORT_PRIO_SECONDARY value must be lo...
Definition scores.qh:133
const int SFL_SORT_PRIO_PRIMARY
Definition scores.qh:134
float game_stopped
Definition stats.qh:81
#define CTS_RECORD
Definition util.qh:98
#define TIME_ENCODED_TOSTRING(n, compact)
Definition util.qh:96
#define LABEL(id)
Definition compiler.qh:34
const int FL_PROJECTILE
Definition constants.qh:85
const int FRAGS_PLAYER_OUT_OF_GAME
Definition constants.qh:5
const int FRAGS_SPECTATOR
Definition constants.qh:4
float time
vector origin
void GameLogEcho(string s)
Definition gamelog.qc:15
bool autocvar_sv_eventlog
Definition gamelog.qh:3
#define IL_EACH(this, cond, body)
Header file that describes the functions related to game items.
#define ITEM_IS_LOOT(item)
Returns whether the item is loot.
Definition spawning.qh:39
#define ClientConnect
Definition _all.inc:238
#define ClientKill
Definition _all.inc:250
#define PutClientInServer
Definition _all.inc:246
bool MapInfo_Get_ByID(int i)
Definition mapinfo.qc:275
float MapInfo_count
Definition mapinfo.qh:166
string MapInfo_Map_bspname
Definition mapinfo.qh:6
const float M_SQRT1_2
Definition mathlib.qh:115
void cvar_set(string name, string value)
float vlen(vector v)
string ftos(float f)
float fabs(float f)
float floor(float f)
void set_movetype(entity this, int mt)
Definition movetypes.qc:4
const int MOVETYPE_NONE
Definition movetypes.qh:129
strcat(_("^F4Countdown stopped!"), "\n^BG", _("Teams are too unbalanced."))
#define NULL
Definition post.qh:14
#define stuffcmd(cl,...)
Definition progsdefs.qh:23
float race_checkpoint
Definition racetimer.qh:8
void Score_NicePrint(entity to)
Prints the scores to the console of a player.
Definition scores.qc:917
entity PlayerScore_Sort(.float field, int teams, bool strict, bool nospectators)
Sorts the players and stores their place in the given field, starting with.
Definition scores.qc:748
vector
Definition self.qh:92
void GetPressedKeys(entity this)
Definition client.qc:1761
void FixClientCvars(entity e)
Definition client.qc:997
int killcount
Definition client.qh:315
bool independent_players
Definition client.qh:310
const int RESPAWN_FORCE
Definition client.qh:326
float race_readTime(string map, float pos)
Definition race.qc:69
void race_SendAll(entity player, bool only_rankings)
Definition race.qc:333
void race_PreparePlayer(entity this)
Definition race.qc:1246
void race_ClearRecords()
Definition race.qc:1285
void race_SpeedAwardFrame(entity player)
Definition race.qc:305
string race_readName(string map, float pos)
Definition race.qc:129
float race_NextCheckpoint(float f)
Definition race.qc:175
void race_checkAndWriteName(entity player)
Definition race.qc:134
IntrusiveList g_racecheckpoints
Definition race.qc:67
void race_RetractPlayer(entity this)
Definition race.qc:1255
void race_AbandonRaceCheck(entity p)
Definition race.qc:1229
bool autocvar_g_allow_checkpoints
Definition race.qh:3
float race_timelimit
Definition race.qh:23
float race_place
Definition race.qh:24
float race_fraglimit
Definition race.qh:21
float race_leadlimit
Definition race.qh:22
int g_race_qualifying
Definition race.qh:13
IntrusiveList g_projectiles
Definition common.qh:58
ClientState CS(Client this)
Definition state.qh:47
float frag_damage
Definition sv_ctf.qc:2322
entity frag_target
Definition sv_ctf.qc:2321
bool autocvar_g_cts_selfdamage
Definition sv_cts.qc:13
void cts_EventLog(string mode, entity actor)
Definition sv_cts.qc:69
void cts_ScoreRules()
Definition sv_cts.qc:55
void havocbot_role_cts(entity this)
Definition sv_cts.qc:19
bool autocvar_g_cts_drop_monster_items
Definition sv_cts.qc:15
void cts_Initialize()
Definition sv_cts.qc:375
bool autocvar_g_cts_removeprojectiles
Definition sv_cts.qc:14
float autocvar_g_cts_finish_kill_delay
Definition sv_cts.qc:12
#define GameRules_score_enabled(value)
Definition sv_rules.qh:41
#define GameRules_scoring_add(client, fld, value)
Definition sv_rules.qh:85
#define GameRules_scoring(teams, spprio, stprio, fields)
Definition sv_rules.qh:58
#define FOREACH_CLIENT(cond, body)
Definition utils.qh:50
#define vdist(v, cmp, f)
Vector distance comparison, avoids sqrt()
Definition vector.qh:8
string record_type
Definition world.qh:55