From 483edaedc79017d7aaaee86f7bfb759bf622012d Mon Sep 17 00:00:00 2001 From: dusty-qw <71472647+dusty-qw@users.noreply.github.com> Date: Fri, 14 Mar 2025 02:43:28 -0700 Subject: [PATCH 01/34] LEAVEMEALONE: players can't bother you in prewar --- include/progs.h | 1 + src/client.c | 12 +++++++++++- src/combat.c | 15 +++++++++++++++ src/commands.c | 30 ++++++++++++++++++++++++++++++ src/match.c | 1 + src/triggers.c | 2 +- src/weapons.c | 23 +++++++++++++++++++++++ 7 files changed, 82 insertions(+), 2 deletions(-) diff --git a/include/progs.h b/include/progs.h index 7479c3c5..e05dd3c5 100644 --- a/include/progs.h +++ b/include/progs.h @@ -953,6 +953,7 @@ typedef struct gedict_s float fIllegalFPSWarnings; // ILLEGALFPS] + qbool leavemealone; float shownick_time; // used to force centerprint is off at desired time clientType_t ct; // client type for client edicts // { timing diff --git a/src/client.c b/src/client.c index 3411931e..a8b8abad 100644 --- a/src/client.c +++ b/src/client.c @@ -1740,7 +1740,7 @@ void PutClientInServer(void) self->classname = "player"; self->s.v.health = 100; self->s.v.takedamage = DAMAGE_AIM; - self->s.v.solid = SOLID_SLIDEBOX; + self->s.v.solid = self->leavemealone ? SOLID_TRIGGER : SOLID_SLIDEBOX; self->s.v.movetype = MOVETYPE_WALK; self->show_hostile = 0; self->s.v.max_health = 100; @@ -3698,6 +3698,16 @@ void PlayerPreThink(void) race_player_pre_think(); + if (self->leavemealone) + { + if ((self->s.v.mins[0] == 0) || (self->s.v.mins[1] == 0)) + { + // This can happen if the world 'squashes' a SOLID_NOT entity, mvdsv will turn into corpse + setsize(self, PASSVEC3(VEC_HULL_MIN), PASSVEC3(VEC_HULL_MAX)); + } + setorigin(self, PASSVEC3(self->s.v.origin)); + } + // brokenankle included here if (self->s.v.button2 || self->brokenankle) { diff --git a/src/combat.c b/src/combat.c index 4df933ba..cd4d4a97 100644 --- a/src/combat.c +++ b/src/combat.c @@ -462,6 +462,21 @@ void T_Damage(gedict_t *targ, gedict_t *inflictor, gedict_t *attacker, float dam return; } + // don't bounce around players in prewar who wish to be left alone + if (match_in_progress != 2 && targ->leavemealone) + { + if (attacker != targ && ((targ->ct == ctPlayer) && (attacker->ct == ctPlayer))) + { + return; + } + else if (dtTELE1 == targ->deathtype // always do tele damage + || dtTELE2 == targ->deathtype // always do tele damage + || dtTELE3 == targ->deathtype) // always do tele damage + { + // telefrags still work, to avoid getting stuck + } + } + // can't damage other players in race if (isRACE() && (attacker != targ)) { diff --git a/src/commands.c b/src/commands.c index ad7b276b..eb226393 100644 --- a/src/commands.c +++ b/src/commands.c @@ -72,6 +72,7 @@ void CTFBasedSpawn(void); // } CTF void FragsDown(void); void FragsUp(void); +void LeaveMeAlone(void); void ListWhoNot(void); void ModStatus1(void); void ModStatus2(void); @@ -390,6 +391,7 @@ const char CD_NODESC[] = "no desc"; #define CD_CTOCT "Show octal charset table" #define CD_CTHEX "Show hexadecimal charset table" #define CD_SHOWNICK "pointed player's info" +#define CD_LEAVEMEALONE "can't shoot/bounce players in prewar" #define CD_TIME5 "set timelimit to 5 mins" #define CD_TIME10 "set timelimit to 10 mins" #define CD_TIME15 "set timelimit to 15 mins" @@ -753,6 +755,7 @@ cmd_t cmds[] = { "sct_hex", ShowCharsetTableHexa, 0, CF_BOTH, CD_CTHEX }, { "about", ShowVersion, 0, CF_BOTH | CF_MATCHLESS, CD_ABOUT }, { "shownick", ShowNick, 0, CF_PLAYER | CF_PARAMS, CD_SHOWNICK }, + { "leavemealone", LeaveMeAlone, 0, CF_PLAYER | CF_PARAMS, CD_LEAVEMEALONE }, { "time5", DEF(TimeSet), 5.0f, CF_PLAYER | CF_SPC_ADMIN, CD_TIME5 }, { "time10", DEF(TimeSet), 10.0f, CF_PLAYER | CF_SPC_ADMIN, CD_TIME10 }, { "time15", DEF(TimeSet), 15.0f, CF_PLAYER | CF_SPC_ADMIN, CD_TIME15 }, @@ -4067,6 +4070,33 @@ void ShowNick(void) self->shownick_time = g_globalvars.time + 0.8; // clear centerprint at this time } +void LeaveMeAlone(void) +{ + if (match_in_progress) + { + return; + } + + if (isRA() || isRACE()) + { + return; + } + + if (self->leavemealone) + { + G_bprint(2, "%s %s\n", self->netname, redtext("no longer wants to be left alone")); + self->s.v.solid = SOLID_SLIDEBOX; + } + else + { + G_bprint(2, "%s %s\n", self->netname, redtext("wants to be left alone")); + self->s.v.solid = SOLID_TRIGGER; + } + + setorigin(self, PASSVEC3(self->s.v.origin)); + self->leavemealone = !self->leavemealone; +} + // qqshka // below predefined settings for usermodes diff --git a/src/match.c b/src/match.c index 0972e3d1..cc4e9aa2 100644 --- a/src/match.c +++ b/src/match.c @@ -914,6 +914,7 @@ static void SM_PrepareClients(void) for (p = world; (p = find_plr(p));) { players[player_count++] = p; + p->leavemealone = false; // can't have this enabled during match } for (i = player_count - 1; i > 0; i--) diff --git a/src/triggers.c b/src/triggers.c index 9cb52f6d..17348f7a 100644 --- a/src/triggers.c +++ b/src/triggers.c @@ -715,7 +715,7 @@ void teleport_touch(void) } // only teleport living creatures - if (ISDEAD(other) || (!isRACE() && (other->s.v.solid != SOLID_SLIDEBOX))) + if (ISDEAD(other) || (!isRACE() && (other->s.v.solid != SOLID_SLIDEBOX) && !other->leavemealone)) { return; } diff --git a/src/weapons.c b/src/weapons.c index 95e116ae..287cc28b 100644 --- a/src/weapons.c +++ b/src/weapons.c @@ -377,6 +377,12 @@ void TraceAttack(float damage, vec3_t dir, qbool send_effects) return; } + //can't touch/damage players who want to be left alone + if (PROG_TO_EDICT(g_globalvars.trace_ent)->ct == ctPlayer && PROG_TO_EDICT(g_globalvars.trace_ent)->leavemealone) + { + return; + } + if (PROG_TO_EDICT(g_globalvars.trace_ent)->s.v.takedamage) { if (PROG_TO_EDICT(g_globalvars.trace_ent)->ct == ctPlayer) @@ -960,6 +966,11 @@ void T_MissileTouch(void) return; } + if (other->leavemealone) + { + return; + } + if (self->voided) { return; @@ -1323,6 +1334,12 @@ void GrenadeTouch(void) return; } + // can't touch players who want to be left alone + if (other->leavemealone) + { + return; + } + if (other->s.v.takedamage) { if (other->ct == ctPlayer) @@ -1517,6 +1534,12 @@ void spike_touch(void) return; } + // can't touch players who want to be left alone + if (other->leavemealone) + { + return; + } + if (self->voided) { return; From 346f855af21579a4c766f868f950babf90a37fad Mon Sep 17 00:00:00 2001 From: dusty-qw <71472647+dusty-qw@users.noreply.github.com> Date: Sun, 25 May 2025 01:04:39 -0700 Subject: [PATCH 02/34] WIPEOUT: fix invisible player interference When a player respawns in wipeout, he will become solid right before teleporting to the spawn point. This can result in him blocking weapon fire from whomever he is spectating at the moment of respawn. --- src/clan_arena.c | 4 ---- src/client.c | 38 ++++++++++++++++++++++++++++++++------ 2 files changed, 32 insertions(+), 10 deletions(-) diff --git a/src/clan_arena.c b/src/clan_arena.c index 873b8eeb..b4cd5372 100644 --- a/src/clan_arena.c +++ b/src/clan_arena.c @@ -1251,15 +1251,11 @@ void CA_player_pre_think(void) { CA_show_greeting(self); - // Set this player to solid so we trigger checkpoints & teleports during move - self->s.v.solid = (ISDEAD(self) ? SOLID_NOT : SOLID_SLIDEBOX); - if ((self->s.v.mins[0] == 0) || (self->s.v.mins[1] == 0)) { // This can happen if the world 'squashes' a SOLID_NOT entity, mvdsv will turn into corpse setsize(self, PASSVEC3(VEC_HULL_MIN), PASSVEC3(VEC_HULL_MAX)); } - setorigin(self, PASSVEC3(self->s.v.origin)); if ((self->ct == ctPlayer) && (ISDEAD(self) || !self->in_play)) diff --git a/src/client.c b/src/client.c index 3411931e..cfb18ec1 100644 --- a/src/client.c +++ b/src/client.c @@ -1740,7 +1740,7 @@ void PutClientInServer(void) self->classname = "player"; self->s.v.health = 100; self->s.v.takedamage = DAMAGE_AIM; - self->s.v.solid = SOLID_SLIDEBOX; + self->s.v.solid = isCA() ? SOLID_NOT : self->leavemealone ? SOLID_TRIGGER : SOLID_SLIDEBOX; self->s.v.movetype = MOVETYPE_WALK; self->show_hostile = 0; self->s.v.max_health = 100; @@ -1939,6 +1939,37 @@ void PutClientInServer(void) } } + if (isCA()) + { + CA_PutClientInServer(); + W_SetCurrentAmmo(); // important shit, not only ammo + teleport_player(self, self->s.v.origin, self->s.v.angles, tele_flags); + + g_globalvars.msg_entity = EDICT_TO_PROG(self); + WriteByte(MSG_ONE, 38 /*svc_updatestatlong*/); + WriteByte(MSG_ONE, 18 /*STAT_MATCHSTARTTIME*/); + WriteLong(MSG_ONE, g_matchstarttime); + +#ifdef BOT_SUPPORT + BotClientEntersEvent(self, spot); +#endif + + // dusty: CA/wipeout must set solid state AFTER the spawn/teleport_player() + // otherwise player will become "solid" while tracking other players and + // get hit by projectiles. + if (match_in_progress) + { + self->s.v.solid = self->in_play ? SOLID_SLIDEBOX : SOLID_NOT; + } + else + { + self->s.v.solid = self->leavemealone ? SOLID_TRIGGER : SOLID_SLIDEBOX; + } + setorigin(self, PASSVEC3(self->s.v.origin)); + + return; + } + if (isRA()) { ra_PutClientInServer(); @@ -2259,11 +2290,6 @@ void PutClientInServer(void) } } - if (isCA()) - { - CA_PutClientInServer(); - } - // remove particular weapons in dmm4 if (deathmatch == 4 && match_in_progress == 2) { From f3916489773cb026b9734f980436ec654ca84d35 Mon Sep 17 00:00:00 2001 From: dusty-qw <71472647+dusty-qw@users.noreply.github.com> Date: Tue, 8 Jul 2025 20:20:51 -0700 Subject: [PATCH 03/34] WIPEOUT: /latejoin --- include/g_local.h | 1 + include/progs.h | 7 ++- src/clan_arena.c | 17 ++++++++ src/commands.c | 96 +++++++++++++++++++++++++++++++++++++++- src/g_userinfo.c | 3 +- src/vote.c | 109 +++++++++++++++++++++++++++++++++++++++++++++- 6 files changed, 227 insertions(+), 6 deletions(-) diff --git a/include/g_local.h b/include/g_local.h index f4398805..ff884639 100644 --- a/include/g_local.h +++ b/include/g_local.h @@ -894,6 +894,7 @@ void CA_player_pre_think(void); void CA_spectator_think(void); void CA_Frame(void); void CA_PutClientInServer(void); +void CA_AddLatePlayer(gedict_t *p, char *team); qbool CA_can_fire(gedict_t *p); // captain.c diff --git a/include/progs.h b/include/progs.h index 7479c3c5..47e801ac 100644 --- a/include/progs.h +++ b/include/progs.h @@ -219,7 +219,8 @@ typedef enum etCaptain, etCoach, etAdmin, - etSuggestColor + etSuggestColor, + etLateJoin } electType_t; // store player votes here @@ -1065,6 +1066,7 @@ typedef struct gedict_s qbool in_limbo; // waiting to respawn during wipeout qbool last_alive_active; // if last alive timer is active qbool no_pain; // if player can take any damage to health or armor + qbool lj_accepted; // if late-join request was accepted float ca_round_frags; float ca_round_kills; float ca_round_dmg; @@ -1081,7 +1083,8 @@ typedef struct gedict_s float seconds_to_respawn; // number of seconds until respawn float escape_time; // number of seconds after "escaping" char *teamcolor; // color of player's team - char cptext[100]; // centerprint for player + char cptext[1024]; // centerprint for player + char ljteam[1024]; // team that player is requesting to join int ca_ammo_grenades; // grenade ammo int tracking_enabled; int round_deaths; // number of times player has died in the round diff --git a/src/clan_arena.c b/src/clan_arena.c index b4cd5372..8418e0f6 100644 --- a/src/clan_arena.c +++ b/src/clan_arena.c @@ -23,6 +23,7 @@ void CA_TeamsStats(void); void CA_SendTeamInfo(gedict_t *t); void print_player_stats(qbool series_over); void CA_OnePlayerStats(gedict_t *p, qbool series_over); +void CA_AddLatePlayer(gedict_t *p, char *team); void EndRound(int alive_team); void show_tracking_info(gedict_t *p); @@ -273,6 +274,22 @@ qbool CA_CheckAlive(gedict_t *p) } } +void CA_AddLatePlayer(gedict_t *p, char *team) +{ + p->ready = 1; + p->ca_ready = 1; + p->lj_accepted = 1; // Set flag to allow team change in FixPlayerTeam + + SetUserInfo(p, "team", team, 0); + stuffcmd_flags(p, STUFFCMD_IGNOREINDEMO, "team \"%s\"\n", team); + G_bprint(2, "%s late-joined team \x90%s\x91\n", p->netname, team); + + p->lj_accepted = 0; // clear the flag immediately + p->ljteam[0] = '\0'; // clear the requested team name + p->can_respawn = false; // can't join mid-round + p->seconds_to_respawn = 999; // don't show countdown +} + void CA_MatchBreak(void) { gedict_t *p; diff --git a/src/commands.c b/src/commands.c index ad7b276b..30d370e0 100644 --- a/src/commands.c +++ b/src/commands.c @@ -209,6 +209,7 @@ void iplist(void); void dmgfrags(void); void no_lg(void); void no_gl(void); +void latejoin(void); void mv_cmd_playback(void); void mv_cmd_record(void); void mv_cmd_stop(void); @@ -455,6 +456,7 @@ const char CD_NODESC[] = "no desc"; #define CD_HDPTOGGLE "toggle allow handicap" #define CD_HANDICAP "toggle handicap level" #define CD_NOWEAPON "toggle allow any weapon" +#define CD_LATEJOIN "join a team after the game started" #define CD_CAM "camera help text" #define CD_TRACKLIST "trackers list" #define CD_FPSLIST "fps list" @@ -828,6 +830,7 @@ cmd_t cmds[] = { "hdptoggle", hdptoggle, 0, CF_BOTH_ADMIN, CD_HDPTOGGLE }, { "handicap", handicap, 0, CF_PLAYER | CF_PARAMS | CF_MATCHLESS, CD_HANDICAP }, { "noweapon", noweapon, 0, CF_PLAYER | CF_PARAMS | CF_SPC_ADMIN, CD_NOWEAPON }, + { "latejoin", latejoin, 0, CF_PLAYER | CF_PARAMS | CF_SPC_ADMIN, CD_LATEJOIN }, { "cam", ShowCamHelp, 0, CF_SPECTATOR | CF_MATCHLESS, CD_CAM }, @@ -2310,7 +2313,7 @@ void ModStatusVote(void) } } -if (!match_in_progress) + if (!match_in_progress) { if ((votes = get_votes(OV_HOOKCLASSIC))) { @@ -5252,6 +5255,97 @@ void no_gl(void) stuffcmd_flags(self, STUFFCMD_IGNOREINDEMO, "cmd noweapon gl\n"); } +void latejoin(void) +{ + int till; + char arg_2[1024]; + gedict_t *p, *electguard; + int team_players = 0, other_team_players = 0; + + if (!match_in_progress) { + return; + } + + if (!isCA()) { + G_sprint(self, 2, "Late-join requests are only allowed during CA or Wipeout.\n"); + return; + } + + if (self->ca_ready) { + G_sprint(self, 2, "You're already on a team.\n"); + return; + } + + // Check if player is already being elected + if (is_elected(self, etLateJoin)) { + G_bprint(2, "%s %s!\n", self->netname, redtext("aborts late join request")); + AbortElect(); + return; + } + + // Check if any election is in progress + if (get_votes(OV_ELECT)) { + G_sprint(self, 2, "An election is already in progress\n"); + return; + } + + // Check election timeout + if ((till = Q_rint(self->v.elect_block_till - g_globalvars.time)) > 0) { + G_sprint(self, 2, "Wait %d second%s!\n", till, count_s(till)); + return; + } + + // Get team argument + if (trap_CmdArgc() < 2) { + G_sprint(self, 2, "Usage: latejoin \n"); + G_sprint(self, 2, "Available teams: %s, %s \n", cvar_string("_k_team1"), cvar_string("_k_team2")); + return; + } + + trap_CmdArgv(1, arg_2, sizeof(arg_2)); + + // Validate team name + if (!streq(arg_2, cvar_string("_k_team1")) && !streq(arg_2, cvar_string("_k_team2"))) { + G_sprint(self, 2, "Invalid team. Must be %s or %s \n", cvar_string("_k_team1"), cvar_string("_k_team2")); + return; + } + + // Count players on each team + for (p = world; (p = find_plr(p));) { + if (p->ca_ready) { + if (streq(getteam(p), arg_2)) { + team_players++; + } else { + other_team_players++; + } + } + } + + if (team_players > other_team_players) { + G_sprint(self, 2, "Team %s already has more players\n", arg_2); + return; + } + + // Store the requested team for later use + snprintf(self->ljteam, sizeof(self->ljteam), arg_2); + //self->ljteam = arg_2; + + // Start the election + self->v.elect = 1; + self->v.elect_type = etLateJoin; + + G_bprint(2, "%s has requested to %s team \x90%s\x91\n", + self->netname, redtext("late-join"), arg_2); + G_bprint(2, "Team \x90%s\x91 members: type %s to approve\n", arg_2, redtext("yes")); + + // Spawn election timeout entity + electguard = spawn(); + electguard->s.v.owner = EDICT_TO_PROG(world); + electguard->classname = "electguard"; + electguard->think = (func_t) ElectThink; + electguard->s.v.nextthink = g_globalvars.time + 30; // 30 second timeout +} + void tracklist(void) { int i; diff --git a/src/g_userinfo.c b/src/g_userinfo.c index 087a8237..a2060094 100644 --- a/src/g_userinfo.c +++ b/src/g_userinfo.c @@ -388,7 +388,8 @@ qbool FixPlayerTeam(char *newteam) { // in CA/wipeout, non-participating players are forced to not have a team. // so we must allow team change if player isn't ca_ready and newteam is "" - if (self->ca_ready || strneq(newteam, "")) + // Exception: Allow team change for approved late join players (lj_accepted flag set by CA_AddLatePlayer) + if ((self->ca_ready || strneq(newteam, "")) && !(self->lj_accepted && streq(newteam, self->ljteam))) { G_sprint(self, 2, "You may %s change team during game\n", redtext("not")); stuffcmd_flags(self, STUFFCMD_IGNOREINDEMO, "team \"%s\"\n", getteam(self)); // sends this to client - so he get right team too diff --git a/src/vote.c b/src/vote.c index 01a85660..b1358e09 100644 --- a/src/vote.c +++ b/src/vote.c @@ -84,6 +84,7 @@ void ElectThink(void) void VoteYes(void) { int votes; + gedict_t *p; if (!get_votes(OV_ELECT)) { @@ -104,6 +105,27 @@ void VoteYes(void) return; } + // For late join elections, check if voter is on the requested team + if (get_elect_type() == etLateJoin) + { + // Find the player being elected + for (p = world; (p = find_client(p));) + { + if (is_elected(p, etLateJoin)) + { + char *requested_team = p->ljteam; + + // Only players on the requested team can vote + if (!self->ca_ready || !streq(getteam(self), requested_team)) + { + G_sprint(self, 2, "Only members of team %s can vote\n", requested_team); + return; + } + break; + } + } + } + // register the vote self->v.elect = 1; @@ -176,6 +198,40 @@ int get_votes_by_value(int fofs, int value) return votes; } +// Count votes from members of a specific team for late join +int get_latejoin_votes(char *team) +{ + int votes = 0; + gedict_t *p; + + for (p = world; (p = find_client(p));) + { + if (p->v.elect && p->ca_ready && streq(getteam(p), team)) + { + votes++; + } + } + + return votes; +} + +// Count eligible voters on a team for late join +int count_team_voters(char *team) +{ + int count = 0; + gedict_t *p; + + for (p = world; (p = find_plr(p));) + { + if (p->ca_ready && streq(getteam(p), team) && !p->s.v.owner) + { + count++; + } + } + + return count; +} + int get_votes_req(int fofs, qbool diff) { float percent = 51; @@ -232,11 +288,15 @@ int get_votes_req(int fofs, qbool diff) percent = cvar("k_vp_suggestcolor"); break; } + else if (el_type == etLateJoin) + { + percent = 51; // Default to 51% for late join + break; + } else { percent = 100; break; // unknown/none election - break; } break; @@ -283,7 +343,28 @@ int get_votes_req(int fofs, qbool diff) vt_req = ceil(percent * (CountPlayers() - CountBots())); } - if (fofs == OV_ELECT) + // Special handling for late join elections + if ((fofs == OV_ELECT) && (get_elect_type() == etLateJoin)) + { + gedict_t *p; + // Find the player being elected + for (p = world; (p = find_client(p));) + { + if (is_elected(p, etLateJoin)) + { + char *requested_team = p->ljteam; + if (requested_team[0]) + { + // Count only team votes and require majority from that team + votes = get_latejoin_votes(requested_team); + vt_req = ceil(percent * count_team_voters(requested_team)); + vt_req = max(1, vt_req); // at least 1 vote needed + } + break; + } + } + } + else if (fofs == OV_ELECT) { vt_req = max(2, vt_req); // if election, at least 2 votes needed } @@ -406,6 +487,11 @@ int get_elect_type(void) { return etSuggestColor; } + + if (is_elected(p, etLateJoin)) + { + return etLateJoin; + } } return etNone; @@ -426,6 +512,12 @@ char* get_elect_type_str(void) case etAdmin: return "Admin"; + + case etLateJoin: + return "Late Join"; + + case etSuggestColor: + return "Suggest Color"; } return "Unknown"; @@ -610,6 +702,19 @@ void vote_check_elect(void) } } + if (match_in_progress && isCA()) + { + if (is_elected(p, etLateJoin)) + { + // Get the requested team from userinfo + char *team = p->ljteam; + if (team[0]) + { + CA_AddLatePlayer(p, team); + } + } + } + AbortElect(); } } From 82f43f5c4f5330d466b81aa54dc15d6f2c9d7e05 Mon Sep 17 00:00:00 2001 From: dusty-qw <71472647+dusty-qw@users.noreply.github.com> Date: Thu, 10 Jul 2025 01:11:05 -0700 Subject: [PATCH 04/34] WIPEOUT: special rules for teams of one To make 1v2 games more interesting: 1) Solo players get an extra life 2) Solo players get regenerating health/armor if they can avoid taking damage for fixed periods of time after getting a kill (5 seconds, then 10, then 15...) --- include/progs.h | 2 + src/clan_arena.c | 131 ++++++++++++++++++++++++++++++++++++++++++++--- src/combat.c | 14 +++++ 3 files changed, 141 insertions(+), 6 deletions(-) diff --git a/include/progs.h b/include/progs.h index 47e801ac..357c700f 100644 --- a/include/progs.h +++ b/include/progs.h @@ -1062,6 +1062,7 @@ typedef struct gedict_s qbool ca_alive; qbool ca_ready; qbool can_respawn; + qbool is_solo; // is player a one-man team? qbool in_play; // is player still fighting? qbool in_limbo; // waiting to respawn during wipeout qbool last_alive_active; // if last alive timer is active @@ -1079,6 +1080,7 @@ typedef struct gedict_s float ca_round_lghit; float ca_round_lgfired; float alive_time; // number of seconds player is in play + float regen_timer; // when the regen timer is started float time_of_respawn; // server time player respawned or round started float seconds_to_respawn; // number of seconds until respawn float escape_time; // number of seconds after "escaping" diff --git a/src/clan_arena.c b/src/clan_arena.c index 8418e0f6..6d79dfa8 100644 --- a/src/clan_arena.c +++ b/src/clan_arena.c @@ -102,6 +102,8 @@ int calc_respawn_time(gedict_t *p, int offset) teamsize++; } + p->is_solo = teamsize == 1 ? 1 : 0; + multiple = bound(3, teamsize+1, 6); // first respawn won't take more than 6 seconds regardless of team size if (isWipeout && (p->round_deaths+offset <= max_deaths)) @@ -112,6 +114,11 @@ int calc_respawn_time(gedict_t *p, int offset) time = p->round_deaths+offset == 1 ? multiple : (p->round_deaths-1+offset) * (multiple*2); } + // If you're the only player on your team, you get one free instant respawn on first death + if (isWipeout && p->is_solo && p->round_deaths+offset == 1) { + time = 0; + } + return time; } @@ -248,6 +255,7 @@ qbool isCA(void) return (isTeam() && cvar("k_clan_arena")); } +// Used to determine value of ca_alive when PutClientInServer() is called qbool CA_CheckAlive(gedict_t *p) { if (p) @@ -539,9 +547,10 @@ void CA_PutClientInServer(void) // previous round will be invisible self->hideentity = 0; - // reset escape time and last_alive every spawn + // reset escape_time, last_alive, and regen_timer every spawn self->escape_time = 0; self->last_alive_active = false; + self->regen_timer = 0; // default to spawning with rl self->s.v.weapon = IT_ROCKET_LAUNCHER; @@ -814,7 +823,43 @@ void CA_check_escape(gedict_t *targ, gedict_t *attacker) // That's cool, but could be written cleaner in calc_respawn_time(). targ->round_deaths--; - G_bprint(2, "%s survives by &cff0%.3f&r seconds!\n", targ->netname, escape_time); + G_bprint(2, "%s survives by &cff0%.0f&r seconds!\n", targ->netname, escape_time*1000); + } +} + +// wipeout: solo players (one-man teams) who don't take damage for 5 seconds +// after earning a frag get their health/armor/ammo regenerated. +void check_solo_regen(gedict_t *p) +{ + int required_time = p->round_kills * 5; + int time_since_kill = p->regen_timer ? g_globalvars.time - p->regen_timer : 0; + + if (!p->is_solo) + { + return; + } + + if (p->regen_timer && time_since_kill > required_time) + { + // regenerate health/armore/ammo. play megahealth sound or secret sound + stuffcmd(p, "play misc/secret.wav\n"); + + if (!((int)self->s.v.items & IT_ARMOR3)) + { + p->s.v.items += IT_ARMOR3; + } + + p->s.v.armorvalue = 200; + p->s.v.armortype = 0.8; + p->s.v.health = 100; + p->s.v.ammo_nails = 200; + p->s.v.ammo_shells = 100; + p->s.v.ammo_rockets = 50; + p->s.v.ammo_cells = 150; + p->ca_ammo_grenades = 6; + + // reset the timer + p->regen_timer = 0; } } @@ -824,6 +869,12 @@ void CA_ClientObituary(gedict_t *targ, gedict_t *attacker) if (cvar("k_clan_arena") == 2) // Wipeout only { + // check if attacker is a solo player and start regen timer + if (attacker->is_solo && !attacker->regen_timer) + { + attacker->regen_timer = g_globalvars.time; + } + // check if targ was a lone survivor waiting for teammate to spawn CA_check_escape(targ, attacker); } @@ -863,6 +914,39 @@ void CA_ClientObituary(gedict_t *targ, gedict_t *attacker) // } } +// check if a team is a solo player on first death +static qbool is_solo_team_first_death(char *team) +{ + gedict_t *p; + int team_size = 0; + gedict_t *team_player = NULL; + + if (!team || cvar("k_clan_arena") != 2) // Only applies to wipeout + { + return false; + } + + for (p = world; (p = find_plr_same_team(p, team));) + { + if (p->ca_ready) + { + team_player = p; + team_size++; + + if (team_size > 1) + { + return false; + } + } + } + + return (team_player + && team_player->is_solo // redundant but free, so why not + && team_player->round_deaths <= 1 // "<= 1" avoids a race condition + && team_player->can_respawn // makes sures player didn't /kill + ); +} + // return 0 if there no alive teams // return 1 if there one alive team and alive_team point to 1 or 2 wich refering to _k_team1 or _k_team2 cvars // return 2 if there at least two alive teams @@ -871,6 +955,7 @@ static int CA_check_alive_teams(int *alive_team) gedict_t *p; qbool few_alive_teams = false; char *first_team = NULL; + char *dead_team = NULL; if (alive_team) { @@ -911,8 +996,26 @@ static int CA_check_alive_teams(int *alive_team) *alive_team = streq(first_team, cvar_string("_k_team1")) ? 1 : 2; } + // Wipeout only: + // Check if the "dead" team is actually a solo player on first death + dead_team = streq(first_team, cvar_string("_k_team1")) ? cvar_string("_k_team2") : cvar_string("_k_team1"); + if (is_solo_team_first_death(dead_team)) + { + return 2; // Both teams still in play - solo player gets instant respawn + } + return 1; } + else + { + // Wipeout only: + // Both teams are "dead" but one or both teams may be a solo player on his first death + if (is_solo_team_first_death(cvar_string("_k_team1")) || + is_solo_team_first_death(cvar_string("_k_team2"))) + { + return 2; // At least one team consists of a solo player on first death + } + } return 0; } @@ -1120,10 +1223,10 @@ void EndRound(int alive_team) "%s", ((alive_team == 1 && team1_score == (CA_wins_required()-1)) || (alive_team == 2 && team2_score == (CA_wins_required()-1))) ? "series" : "round"); - if ((loser_respawn_time < 2) && (loser_respawn_time > 0)) + if ((loser_respawn_time < 1) && (loser_respawn_time > 0)) { - G_cp2all("Team \x90%s\x91 wins the %s!\n\n\nTeam %s needed %.3f more seconds", - cvar_string(va("_k_team%d", alive_team)), round_or_series, cvar_string(va("_k_team%d", loser_team)), loser_respawn_time); + G_cp2all("Team \x90%s\x91 wins the %s!\n\n\nTeam %s needed %.0f ms longer", + cvar_string(va("_k_team%d", alive_team)), round_or_series, cvar_string(va("_k_team%d", loser_team)), loser_respawn_time*1000); } else { G_cp2all("Team \x90%s\x91 wins the %s!", @@ -1305,6 +1408,12 @@ void CA_player_pre_think(void) self->alive_time = g_globalvars.time - self->time_of_respawn; } + // wipeout: if you're a solo and waiting for health regen + if (cvar("k_clan_arena") == 2 && self->is_solo && self->regen_timer) + { + check_solo_regen(self); + } + // take no damage to health/armor within 1 second of respawn or during endround if (self->in_play && ((self->alive_time >= 1) || !self->round_deaths) && !ca_round_pause) { @@ -1429,6 +1538,16 @@ void CA_Frame(void) } } } + + // you're a solo player... prioritize regen info + else if (p->is_solo && p->regen_timer) + { + int countdown = max(1, (p->round_kills*5) - (int)(g_globalvars.time - p->regen_timer) + 1 ); + snprintf(p->cptext, sizeof(p->cptext), "\n\n\n\n\n\n%s: %d\n\n\n\n", + "regenerating health", countdown); + + G_centerprint(p, "%s", p->cptext); + } // both you and the enemy are the last alive on your team else if (p->in_play && p->alive_time > 2 && last_alive && e_last_alive) { @@ -1464,7 +1583,7 @@ void CA_Frame(void) } } - // check if there exist only one team with alive players and others are eluminated, if so then its time to start ca countdown + // check if there exist only one team with alive players and others are eliminated, if so then its time to start ca countdown if (ra_match_fight == 2 || (ra_match_fight == 1 && ca_round_pause == 1)) { int alive_team = 0; diff --git a/src/combat.c b/src/combat.c index 4df933ba..b73176e1 100644 --- a/src/combat.c +++ b/src/combat.c @@ -444,6 +444,7 @@ void T_Damage(gedict_t *targ, gedict_t *inflictor, gedict_t *attacker, float dam float native_damage = damage; // save damage before apply any modificator char *attackerteam, *targteam, *attackername, *victimname; qbool tp4teamdmg = false; + qbool isWipeout = cvar("k_clan_arena") == 2; //midair and instagib float playerheight = 0, midheight = 0; @@ -508,6 +509,19 @@ void T_Damage(gedict_t *targ, gedict_t *inflictor, gedict_t *attacker, float dam return; } } + + // Wipeout solo players only: + // damage was taken, so reset regen timer if one was started + if (isWipeout && targ->is_solo && targ->regen_timer && attacker != targ) + { + // allow a second of forgiveness, otherwise the same fight + // that started the timer might also stop it. + if (g_globalvars.time - targ->regen_timer > 1.0) + { + stuffcmd(targ, "play boss2/idle.wav\n"); + targ->regen_timer = 0; + } + } } if ((int)cvar("k_midair")) From 9ba5ee6ce3cf9742f25acf1489b3457633cb72cb Mon Sep 17 00:00:00 2001 From: dusty-qw <71472647+dusty-qw@users.noreply.github.com> Date: Thu, 10 Jul 2025 02:11:54 -0700 Subject: [PATCH 05/34] WIPEOUT: remove alive_time field --- include/progs.h | 1 - src/clan_arena.c | 24 +++++++++++------------- 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/include/progs.h b/include/progs.h index 357c700f..bcd242e9 100644 --- a/include/progs.h +++ b/include/progs.h @@ -1079,7 +1079,6 @@ typedef struct gedict_s float ca_round_rldirect; float ca_round_lghit; float ca_round_lgfired; - float alive_time; // number of seconds player is in play float regen_timer; // when the regen timer is started float time_of_respawn; // server time player respawned or round started float seconds_to_respawn; // number of seconds until respawn diff --git a/src/clan_arena.c b/src/clan_arena.c index 6d79dfa8..a66d9204 100644 --- a/src/clan_arena.c +++ b/src/clan_arena.c @@ -1369,6 +1369,8 @@ void CA_player_pre_think(void) { if (isCA()) { + float alive_time = self->in_play ? g_globalvars.time - self->time_of_respawn : 0; + CA_show_greeting(self); if ((self->s.v.mins[0] == 0) || (self->s.v.mins[1] == 0)) @@ -1403,11 +1405,6 @@ void CA_player_pre_think(void) track_player(self); // enable tracking by default while dead } - if (self->in_play) - { - self->alive_time = g_globalvars.time - self->time_of_respawn; - } - // wipeout: if you're a solo and waiting for health regen if (cvar("k_clan_arena") == 2 && self->is_solo && self->regen_timer) { @@ -1415,7 +1412,7 @@ void CA_player_pre_think(void) } // take no damage to health/armor within 1 second of respawn or during endround - if (self->in_play && ((self->alive_time >= 1) || !self->round_deaths) && !ca_round_pause) + if (self->in_play && ((alive_time >= 1) || !self->round_deaths) && !ca_round_pause) { self->no_pain = false; } @@ -1498,6 +1495,7 @@ void CA_Frame(void) // if k_clan_arena is 2, we're playing wipeout if (ra_match_fight == 2 && !ca_round_pause && cvar("k_clan_arena") == 2) { + float alive_time; int last_alive; int e_last_alive; char str_last_alive[25]; @@ -1505,6 +1503,7 @@ void CA_Frame(void) for (p = world; (p = find_plr(p));) { + alive_time = p->in_play ? g_globalvars.time - p->time_of_respawn : 0; last_alive = (int)ceil(last_alive_time(p)); e_last_alive = (int)ceil(enemy_last_alive_time(p)); @@ -1526,7 +1525,7 @@ void CA_Frame(void) k_respawn(p, true); p->seconds_to_respawn = calc_respawn_time(p, 1); - p->time_of_respawn = g_globalvars.time; // resets alive_time to 0 + p->time_of_respawn = g_globalvars.time; // resets alive_time calculations to 0 } else { @@ -1538,7 +1537,6 @@ void CA_Frame(void) } } } - // you're a solo player... prioritize regen info else if (p->is_solo && p->regen_timer) { @@ -1549,7 +1547,7 @@ void CA_Frame(void) G_centerprint(p, "%s", p->cptext); } // both you and the enemy are the last alive on your team - else if (p->in_play && p->alive_time > 2 && last_alive && e_last_alive) + else if (p->in_play && alive_time > 2 && last_alive && e_last_alive) { snprintf(str_last_alive, sizeof(str_last_alive), "%d", last_alive); snprintf(p->cptext, sizeof(p->cptext), "\n\n\n\n\n\n%s\n\n\n%s\n\n\n\n", @@ -1558,7 +1556,7 @@ void CA_Frame(void) G_centerprint(p, "%s", p->cptext); } // you're the last alive on your team versus two or more enemies... hide! - else if (p->in_play && p->alive_time > 2 && last_alive) + else if (p->in_play && alive_time > 2 && last_alive) { snprintf(str_last_alive, sizeof(str_last_alive), "%d", last_alive); snprintf(p->cptext, sizeof(p->cptext), "\n\n\n\n\n\n%s\n\n\n%s\n\n\n\n", @@ -1567,7 +1565,7 @@ void CA_Frame(void) G_centerprint(p, "%s", p->cptext); } // only one enemy remains... find him! - else if (p->in_play && p->alive_time > 2 && e_last_alive) + else if (p->in_play && alive_time > 2 && e_last_alive) { snprintf(str_e_last_alive, sizeof(str_e_last_alive), "%d", e_last_alive); snprintf(p->cptext, sizeof(p->cptext), "\n\n\n\n\n\n%s\n\n\n%s\n\n\n\n", @@ -1575,7 +1573,7 @@ void CA_Frame(void) G_centerprint(p, "%s", p->cptext); } - else if (p->in_play && p->alive_time > 2) + else if (p->in_play && alive_time > 2) { snprintf(p->cptext, sizeof(p->cptext), " "); G_centerprint(p, "%s", p->cptext); @@ -1662,7 +1660,7 @@ void CA_Frame(void) if (p->ca_ready) { - p->time_of_respawn = g_globalvars.time; // resets alive_time to 0 + p->time_of_respawn = g_globalvars.time; // resets alive_time calculations to 0 } } From 036453aab443e2f5f49b63d660418cad470b858c Mon Sep 17 00:00:00 2001 From: dusty-qw <71472647+dusty-qw@users.noreply.github.com> Date: Thu, 10 Jul 2025 18:46:08 -0700 Subject: [PATCH 06/34] WIPEOUT: use custom spawn config --- src/clan_arena.c | 105 +++++++++++++++++++++++++++++++++++++++++++++++ src/client.c | 33 ++++++++++++++- 2 files changed, 136 insertions(+), 2 deletions(-) diff --git a/src/clan_arena.c b/src/clan_arena.c index a66d9204..b8f3879c 100644 --- a/src/clan_arena.c +++ b/src/clan_arena.c @@ -4,6 +4,36 @@ #include "g_local.h" +typedef struct wipeout_spawn_config_t +{ + vec3_t origin; // spawn point coordinates + char *name; // spawn point name (for debugging) + float custom_radius; // custom radius for this spawn (0 = use default) +} wipeout_spawn_config; + +typedef struct wipeout_map_spawns_t +{ + char *mapname; + wipeout_spawn_config *spawns; + int spawn_count; +} wipeout_map_spawns; + +// Some spawns require a custom radius to prevent abuse +// Using 0 defaults to a radius of 84 units +static wipeout_spawn_config dm3_spawns[] = { + { { -880, -232, -16 }, "tele/sng", 128 }, + { { 192, -208, -176 }, "big>ra", 0 }, + { { 1472, -928, -24 }, "ya box", 0 }, + { { 1520, 432, -88 }, "rl", 190 }, + { { -632, -680, -16 }, "tele/ra", 128 }, + { { 512, 768, 216 }, "lifts", 128 } +}; + +static wipeout_map_spawns wipeout_spawn_configs[] = { + { "dm3", dm3_spawns, sizeof(dm3_spawns) / sizeof(dm3_spawns[0]) }, + { NULL, NULL, 0 } // terminator +}; + static int round_num; static int team1_score; static int team2_score; @@ -27,6 +57,11 @@ void CA_AddLatePlayer(gedict_t *p, char *team); void EndRound(int alive_team); void show_tracking_info(gedict_t *p); +// Wipeout spawn management functions +static wipeout_spawn_config* WO_FindSpawnConfig(vec3_t origin); +float WO_GetSpawnRadius(vec3_t origin); +void WO_InitializeSpawns(void); + gedict_t* ca_find_player(gedict_t *p, gedict_t *observer) { char *team = getteam(observer); @@ -227,6 +262,11 @@ void SM_PrepareCA(void) return; } + if (cvar("k_clan_arena") == 2) + { + WO_InitializeSpawns(); // init wipeout spawns + } + team1_score = team2_score = 0; round_num = 1; @@ -1706,3 +1746,68 @@ void CA_Frame(void) } } } + +// Find spawn configuration for a given origin +static wipeout_spawn_config* WO_FindSpawnConfig(vec3_t origin) +{ + int i, j; + + if (cvar("k_clan_arena") != 2) // Only for wipeout mode + { + return NULL; + } + + // Find current map configuration + for (i = 0; wipeout_spawn_configs[i].mapname; i++) + { + if (streq(mapname, wipeout_spawn_configs[i].mapname)) + { + // Search for matching spawn point + for (j = 0; j < wipeout_spawn_configs[i].spawn_count; j++) + { + if (VectorCompare(origin, wipeout_spawn_configs[i].spawns[j].origin)) + { + return &wipeout_spawn_configs[i].spawns[j]; + } + } + break; + } + } + + return NULL; +} + +// Get custom spawn radius for a spawn point +float WO_GetSpawnRadius(vec3_t origin) +{ + wipeout_spawn_config *config = WO_FindSpawnConfig(origin); + + if (config && config->custom_radius > 0) + { + return config->custom_radius; + } + + return 0; // Use default radius +} + +// Initialize wipeout spawns (can be called to reload configurations) +void WO_InitializeSpawns(void) +{ + if (cvar("k_clan_arena") == 2) + { + int i; + for (i = 0; wipeout_spawn_configs[i].mapname; i++) + { + if (streq(mapname, wipeout_spawn_configs[i].mapname)) + { + if (cvar("developer")) + { + G_bprint(2, "Wipeout: Using custom spawn configuration for %s (%d spawns)\n", + mapname, wipeout_spawn_configs[i].spawn_count); + } + + break; + } + } + } +} diff --git a/src/client.c b/src/client.c index cfb18ec1..45aa4c08 100644 --- a/src/client.c +++ b/src/client.c @@ -57,6 +57,8 @@ void SendSpecInfo(gedict_t *spec, gedict_t *target_client); void del_from_specs_favourites(gedict_t *rm); void item_megahealth_rot(void); +float WO_GetSpawnRadius(vec3_t origin); + extern int g_matchstarttime; void CheckAll(void) @@ -1012,6 +1014,26 @@ float CheckSpawnPoint(vec3_t v) return false; } +/* + ============ + GetEffectiveSpawnRadius + + Returns the effective spawn radius for a spawn point, considering wipeout custom radius + ============ + */ +static float GetEffectiveSpawnRadius(gedict_t *spot, float default_radius) +{ + if (cvar("k_clan_arena") == 2) + { + float custom_radius = WO_GetSpawnRadius(spot->s.v.origin); + if (custom_radius > 0) + { + return custom_radius; + } + } + return default_radius; +} + /* ============ SelectSpawnPoint @@ -1029,6 +1051,7 @@ gedict_t* Sub_SelectSpawnPoint(char *spawnname) int pcount; int k_spw = cvar("k_spw"); int weight_sum = 0; // used by "fair spawns" + float spawn_radius = 84; // default spawn check radius // testinfo_player_start is only found in regioned levels spot = find(world, FOFCLSN, "testplayerstart"); @@ -1060,8 +1083,11 @@ gedict_t* Sub_SelectSpawnPoint(char *spawnname) totalspots++; pcount = 0; + // Get spawn-specific radius if defined + float spot_radius = GetEffectiveSpawnRadius(spot, spawn_radius); + // find count of nearby players for 'spot' - for (thing = world; (thing = trap_findradius(thing, spot->s.v.origin, 84));) + for (thing = world; (thing = trap_findradius(thing, spot->s.v.origin, spot_radius));) { if ((thing->ct != ctPlayer) || ISDEAD(thing) || (thing == self)) { @@ -1132,7 +1158,10 @@ gedict_t* Sub_SelectSpawnPoint(char *spawnname) trap_makevectors(isRA() ? spot->mangle : spot->s.v.angles); // stupid ra uses mangles instead of angles - for (thing = world; (thing = trap_findradius(thing, spot->s.v.origin, 84));) + // Get spawn-specific radius for fallback spawn too + float fallback_radius = GetEffectiveSpawnRadius(spot, spawn_radius); + + for (thing = world; (thing = trap_findradius(thing, spot->s.v.origin, fallback_radius));) { if ((thing->ct != ctPlayer) || ISDEAD(thing) || (thing == self)) { From 8ab40a7e731202505d19e48087dc8a51700da97d Mon Sep 17 00:00:00 2001 From: dusty-qw <71472647+dusty-qw@users.noreply.github.com> Date: Fri, 11 Jul 2025 03:29:00 -0700 Subject: [PATCH 07/34] WIPEOUT: spawn radius doesn't apply through walls --- src/clan_arena.c | 2 +- src/client.c | 27 +++++++++++++++++++++++++-- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/src/clan_arena.c b/src/clan_arena.c index b8f3879c..83dbc8d1 100644 --- a/src/clan_arena.c +++ b/src/clan_arena.c @@ -24,7 +24,7 @@ static wipeout_spawn_config dm3_spawns[] = { { { -880, -232, -16 }, "tele/sng", 128 }, { { 192, -208, -176 }, "big>ra", 0 }, { { 1472, -928, -24 }, "ya box", 0 }, - { { 1520, 432, -88 }, "rl", 190 }, + { { 1520, 432, -88 }, "rl", 300 }, { { -632, -680, -16 }, "tele/ra", 128 }, { { 512, 768, 216 }, "lifts", 128 } }; diff --git a/src/client.c b/src/client.c index 45aa4c08..06c22733 100644 --- a/src/client.c +++ b/src/client.c @@ -1080,11 +1080,13 @@ gedict_t* Sub_SelectSpawnPoint(char *spawnname) for (spot = world; (spot = find(spot, FOFCLSN, spawnname));) { + float spot_radius; + totalspots++; pcount = 0; // Get spawn-specific radius if defined - float spot_radius = GetEffectiveSpawnRadius(spot, spawn_radius); + spot_radius = GetEffectiveSpawnRadius(spot, spawn_radius); // find count of nearby players for 'spot' for (thing = world; (thing = trap_findradius(thing, spot->s.v.origin, spot_radius));) @@ -1094,6 +1096,16 @@ gedict_t* Sub_SelectSpawnPoint(char *spawnname) continue; // ignore non player, or dead played, or self } + // For wipeout mode, check line of sight before blocking spawn + if (cvar("k_clan_arena") == 2) + { + traceline(PASSVEC3(spot->s.v.origin), PASSVEC3(thing->s.v.origin), true, self); + if (g_globalvars.trace_fraction < 1) + { + continue; // Wall/obstruction between spawn and player, don't discard spawn + } + } + // k_spw 2 and 3 and 4 feature, if player is spawned not far away and run // around spot - treat this spot as not valid. // k_1spawn store this "not far away" time. @@ -1155,11 +1167,12 @@ gedict_t* Sub_SelectSpawnPoint(char *spawnname) if (!match_in_progress || k_spw == 1 || (k_spw == 2 && !k_checkx)) { vec3_t v1, v2; + float fallback_radius; trap_makevectors(isRA() ? spot->mangle : spot->s.v.angles); // stupid ra uses mangles instead of angles // Get spawn-specific radius for fallback spawn too - float fallback_radius = GetEffectiveSpawnRadius(spot, spawn_radius); + fallback_radius = GetEffectiveSpawnRadius(spot, spawn_radius); for (thing = world; (thing = trap_findradius(thing, spot->s.v.origin, fallback_radius));) { @@ -1168,6 +1181,16 @@ gedict_t* Sub_SelectSpawnPoint(char *spawnname) continue; // ignore non player, or dead played, or self } + // For wipeout mode, check line of sight before moving player + if (cvar("k_clan_arena") == 2) + { + traceline(PASSVEC3(spot->s.v.origin), PASSVEC3(thing->s.v.origin), true, self); + if (g_globalvars.trace_fraction < 1) + { + continue; // Wall/obstruction between spawn and player, don't move them + } + } + VectorMA(thing->s.v.origin, -15.0, g_globalvars.v_up, v1); VectorMA(v1, 160.0, g_globalvars.v_forward, v2); From ad7a11a2e0636459ebdc88d09aaca62c2f5ebb82 Mon Sep 17 00:00:00 2001 From: dusty-qw <71472647+dusty-qw@users.noreply.github.com> Date: Fri, 11 Jul 2025 12:51:10 -0700 Subject: [PATCH 08/34] WIPEOUT: smoother player tracking while dead Now using trackent, which utilizes the client's built-in interpolation for spectators. Simplified spectator tracking to switch to an alive teammate when current tracking target dies. --- src/clan_arena.c | 85 ++++++++++++++++++------------------------------ src/client.c | 20 ++++++++++++ 2 files changed, 51 insertions(+), 54 deletions(-) diff --git a/src/clan_arena.c b/src/clan_arena.c index 83dbc8d1..fb142f78 100644 --- a/src/clan_arena.c +++ b/src/clan_arena.c @@ -366,10 +366,6 @@ void CA_MatchBreak(void) void track_player(gedict_t *observer) { gedict_t *player = ca_get_player(observer); - vec3_t delta; - float vlen; - int follow_distance; - int upward_distance; if (player && !observer->in_play && observer->tracking_enabled) { @@ -396,37 +392,12 @@ void track_player(gedict_t *observer) observer->track_target = player; } - // { spectate in 1st person - follow_distance = -10; - upward_distance = 0; - observer->hideentity = EDICT_TO_PROG(player); // in this mode we want to hide player model for watcher's view - VectorCopy(player->s.v.v_angle, observer->s.v.angles); - // } - - observer->s.v.fixangle = true; // force client v_angle (disable in 3rd person view) - - trap_makevectors(player->s.v.angles); - VectorMA(player->s.v.origin, follow_distance, g_globalvars.v_forward, observer->s.v.origin); - VectorMA(observer->s.v.origin, upward_distance, g_globalvars.v_up, observer->s.v.origin); - - // avoid positionning in walls - traceline(PASSVEC3(player->s.v.origin), PASSVEC3(observer->s.v.origin), false, player); - VectorCopy(g_globalvars.trace_endpos, observer->s.v.origin); + // Use trackent for smooth tracking + observer->trackent = NUM_FOR_EDICT(player); + observer->hideentity = EDICT_TO_PROG(player); // Hide tracked player model - if (g_globalvars.trace_fraction == 1) - { - VectorCopy(g_globalvars.trace_endpos, observer->s.v.origin); - VectorMA(observer->s.v.origin, 10, g_globalvars.v_forward, observer->s.v.origin); - } - else - { - VectorSubtract(g_globalvars.trace_endpos, player->s.v.origin, delta); - vlen = VectorLength(delta); - vlen = vlen - 40; - VectorNormalize(delta); - VectorScale(delta, vlen, delta); - VectorAdd(player->s.v.origin, delta, observer->s.v.origin); - } + // Lock observer's orientation to player POV + observer->s.v.movetype = MOVETYPE_LOCK; // set observer's health/armor/ammo/weapon to match the player's observer->s.v.ammo_nails = player->s.v.ammo_nails; @@ -442,17 +413,14 @@ void track_player(gedict_t *observer) observer->weaponmodel = player->weaponmodel; observer->s.v.weaponframe = player->s.v.weaponframe; - // smooth playing for ezq / zq - observer->s.v.movetype = MOVETYPE_LOCK; - show_tracking_info(observer); } - - if (!player || !observer->tracking_enabled) + else { - // restore movement and show racer entity - observer->s.v.movetype = MOVETYPE_NOCLIP; + // Clear tracking + observer->trackent = 0; observer->hideentity = 0; + observer->s.v.movetype = MOVETYPE_NOCLIP; // set health/item values back to nothing observer->s.v.ammo_nails = 0; @@ -641,6 +609,7 @@ void CA_PutClientInServer(void) // tracking enabled by default self->tracking_enabled = 1; + self->trackent = 0; // Initialize trackent for dead players self->in_play = false; self->round_deaths++; //increment death count for wipeout @@ -766,9 +735,9 @@ void CA_SendTeamInfo(gedict_t *t) break; } - if (t->trackent && (t->trackent == NUM_FOR_EDICT(p))) + if (t->ct == ctSpec && t->trackent && (t->trackent == NUM_FOR_EDICT(p))) { - continue; // we pseudo speccing such player, no point to send info about him + continue; // if we're spectating the player, don't send info about him } if (p->ca_ready || match_in_progress != 2) // be sure to send info if in prewar @@ -1488,26 +1457,34 @@ void CA_player_pre_think(void) void CA_spectator_think(void) { - gedict_t *p; + gedict_t *target, *teammate; + int id; - p = PROG_TO_EDICT(self->s.v.goalentity); // who we are spectating + target = PROG_TO_EDICT(self->s.v.goalentity); // who we are spectating - if (p->ct == ctPlayer && !p->in_play && p->tracking_enabled) - { - // if the player you're observing is following someone else, hide the player model - self->hideentity = EDICT_TO_PROG(p->track_target); - } - else + // If spectating a dead player, switch to an alive teammate + if (target && target->ct == ctPlayer && !target->in_play) { - self->hideentity = 0; + // Find any alive teammate + teammate = ca_find_player(world, target); + if (teammate && teammate->in_play && teammate != target) + { + // Use stuffcmd to switch the spectator to the alive teammate + if ((id = GetUserID(teammate)) > 0) + { + stuffcmd_flags(self, STUFFCMD_IGNOREINDEMO, "track %d\n", id); + } + } } - if (p->ct == ctPlayer) + // Get the current viewing target (may have changed due to stuffcmd) + target = PROG_TO_EDICT(self->s.v.goalentity); + if (target && target->ct == ctPlayer) { if (match_in_progress == 2 && ra_match_fight == 2 && round_time > 2 && !ca_round_pause) { // any centerprint the player sees is sent to the spec - G_centerprint(self, "%s\n", p->cptext); + G_centerprint(self, "%s\n", target->cptext); } } } diff --git a/src/client.c b/src/client.c index 06c22733..c90fffac 100644 --- a/src/client.c +++ b/src/client.c @@ -2895,6 +2895,7 @@ void set_important_fields(gedict_t *p) void ClientDisconnect(void) { extern void mv_stop_playback(void); + gedict_t *spec; k_nochange = 0; // force recalculate frags scores @@ -2909,6 +2910,25 @@ void ClientDisconnect(void) del_from_specs_favourites(self); + // Clean up spectators tracking this player + for (spec = world; (spec = find_client(spec));) + { + if (spec->ct == ctSpec) + { + // Check if spectator is tracking the disconnecting player + if (spec->trackent == NUM_FOR_EDICT(self)) + { + spec->trackent = 0; + } + + // Check if spectator's goalentity is the disconnecting player + if (PROG_TO_EDICT(spec->s.v.goalentity) == self) + { + spec->s.v.goalentity = EDICT_TO_PROG(world); + } + } + } + ra_ClientDisconnect(); if (match_in_progress == 2 && self->ct == ctPlayer) From c1b9c6ad540b3325046a4cf37acd140b33013232 Mon Sep 17 00:00:00 2001 From: dusty-qw <71472647+dusty-qw@users.noreply.github.com> Date: Sat, 12 Jul 2025 00:09:12 -0700 Subject: [PATCH 09/34] WIPEOUT: words --- src/clan_arena.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/clan_arena.c b/src/clan_arena.c index fb142f78..4928fbc1 100644 --- a/src/clan_arena.c +++ b/src/clan_arena.c @@ -832,7 +832,7 @@ void CA_check_escape(gedict_t *targ, gedict_t *attacker) // That's cool, but could be written cleaner in calc_respawn_time(). targ->round_deaths--; - G_bprint(2, "%s survives by &cff0%.0f&r seconds!\n", targ->netname, escape_time*1000); + G_bprint(2, "%s survives by &cff0%.0f&r milliseconds!\n", targ->netname, escape_time*1000); } } @@ -1234,7 +1234,7 @@ void EndRound(int alive_team) if ((loser_respawn_time < 1) && (loser_respawn_time > 0)) { - G_cp2all("Team \x90%s\x91 wins the %s!\n\n\nTeam %s needed %.0f ms longer", + G_cp2all("Team \x90%s\x91 wins the %s!\n\n\nTeam %s needed %.0f ms to respawn", cvar_string(va("_k_team%d", alive_team)), round_or_series, cvar_string(va("_k_team%d", loser_team)), loser_respawn_time*1000); } else { From 5268aa76110bdd44da15dc3638488207ded82880 Mon Sep 17 00:00:00 2001 From: blaze Date: Tue, 2 Sep 2025 00:38:26 -0700 Subject: [PATCH 10/34] SOCDv2 --- include/g_local.h | 2 ++ include/progs.h | 5 +++-- src/client.c | 13 ++++++------- src/commands.c | 17 +++++------------ src/g_utils.c | 21 +++++++++++++++++++++ src/match.c | 15 +++++++++++++++ src/stats.c | 5 +++-- 7 files changed, 55 insertions(+), 23 deletions(-) diff --git a/include/g_local.h b/include/g_local.h index b14d2a86..83289ac9 100644 --- a/include/g_local.h +++ b/include/g_local.h @@ -455,6 +455,8 @@ char* clean_string(char *s); void visible_to(gedict_t *viewer, gedict_t *first, int len, byte *visible); +qbool socd_movement_assisted(gedict_t *p); + // Work around for the fact that QVM dos not support ".*s" in printf() family functions. // It retuns dots array filled with dots, amount of dots depends of how long cmd name and longest cmd name. char* make_dots(char *dots, size_t dots_len, int cmd_max_len, char *cmd); diff --git a/include/progs.h b/include/progs.h index 39c0bcc0..18be4d64 100644 --- a/include/progs.h +++ b/include/progs.h @@ -31,6 +31,7 @@ #define LGCMODE_MAX_DISTANCE 700 #define LGCMODE_DISTANCE_BUCKETS 20 #define LGCMODE_BUCKET_DISTANCE (LGCMODE_MAX_DISTANCE / LGCMODE_DISTANCE_BUCKETS) +#define SOCD_DETECTION_VERSION "SOCDv2" typedef struct shared_edict_s { @@ -947,8 +948,8 @@ typedef struct gedict_s // SOCD detectioin float fStrafeChangeCount; float fFramePerfectStrafeChangeCount; - int socdDetected; - int socdChecksCount; + int socdDetectionCount; + int socdValidationCount; float fLastSideMoveSpeed; int matchStrafeChangeCount; int matchPerfectStrafeCount; diff --git a/src/client.c b/src/client.c index 8ef99818..5ccec94c 100644 --- a/src/client.c +++ b/src/client.c @@ -1659,8 +1659,8 @@ void ClientConnect() } // SOCD - self->socdChecksCount = 0; - self->socdDetected = 0; + self->socdValidationCount = 0; + self->socdDetectionCount = 0; self->fStrafeChangeCount = 0; self->fFramePerfectStrafeChangeCount = 0; self->fLastSideMoveSpeed = 0; @@ -3569,16 +3569,15 @@ void PlayerPreThink() { int k_allow_socd_warning = cvar("k_allow_socd_warning"); - self->socdDetected += 1; - if ((!match_in_progress) && (!self->isBot) && k_allow_socd_warning && (self->ct == ctPlayer)) + if ((!match_in_progress) && (!self->isBot) && k_allow_socd_warning && (self->ct == ctPlayer) && (self->socdDetectionCount >= 3)) { G_bprint(PRINT_HIGH, - "Warning! %s: Movement assistance detected. Please disable iDrive or keyboard strafe assistance features.\n", - self->netname); + "[%s] Warning! %s: Movement assistance detected. Please disable iDrive or keyboard strafe assistance features.\n", + SOCD_DETECTION_VERSION, self->netname); } } - self->socdChecksCount += 1; + self->socdValidationCount += 1; self->fStrafeChangeCount = 0; self->fFramePerfectStrafeChangeCount = 0; } diff --git a/src/commands.c b/src/commands.c index 662afd02..7a7cf913 100644 --- a/src/commands.c +++ b/src/commands.c @@ -8133,18 +8133,11 @@ void fcheck() { if ((p->ct == ctPlayer) && (!p->isBot)) { - if (p->socdDetected > 0) - { - G_bprint(2, "%s: %s:%.1f%% (%d/%d). SOCD movement assistance detected!\n", p->netname, redtext("Perfect strafes"), - p->totalStrafeChangeCount > 0 ? 100.0 * p->totalPerfectStrafeCount / p->totalStrafeChangeCount : 0.0, - p->totalPerfectStrafeCount, p->totalStrafeChangeCount); - } - else - { - G_bprint(2, "%s: %s:%.1f%% (%d/%d)\n", p->netname, redtext("Perfect strafes"), - p->totalStrafeChangeCount > 0 ? 100.0 * p->totalPerfectStrafeCount / p->totalStrafeChangeCount : 0.0, - p->totalPerfectStrafeCount, p->totalStrafeChangeCount); - } + G_bprint(2, "[%s] %s: %s:%.1f%% (%d/%d) %s:%d/%d%s\n", SOCD_DETECTION_VERSION, p->netname, redtext("Perfect strafes"), + p->totalStrafeChangeCount > 0 ? 100.0 * p->totalPerfectStrafeCount / p->totalStrafeChangeCount : 0.0, + p->totalPerfectStrafeCount, p->totalStrafeChangeCount, redtext("SOCD detections"), + p->socdDetectionCount, p->socdValidationCount, + socd_movement_assisted(p) ? ". SOCD movement assistance detected!" : ""); } } return; diff --git a/src/g_utils.c b/src/g_utils.c index c3bd1d11..b251c8be 100644 --- a/src/g_utils.c +++ b/src/g_utils.c @@ -2816,3 +2816,24 @@ char* make_dots(char *dots, size_t dots_len, int cmd_max_len, char *cmd) dots[len] = 0; return dots; } + +qbool socd_movement_assisted(gedict_t *p) +{ + if (p->totalStrafeChangeCount < 200 || p->socdDetectionCount < 5) + { + return false; + } + + if ((float)p->totalPerfectStrafeCount / p->totalStrafeChangeCount > 0.58f) + { + return true; + } + + if (p->socdValidationCount > 0 && + ((float)p->socdDetectionCount / p->socdValidationCount) >= 0.10f) + { + return true; + } + + return false; +} \ No newline at end of file diff --git a/src/match.c b/src/match.c index ae89c77d..04bd18b7 100644 --- a/src/match.c +++ b/src/match.c @@ -890,6 +890,21 @@ static void SM_PrepareClients() trap_executecmd(); // <- this really needed initial_match_spawns = true; + + for (p = world; (p = find_plr(p));) + { + p->socdDetectionCount = 0; + p->socdValidationCount = 0; + p->fStrafeChangeCount = 0; + p->fFramePerfectStrafeChangeCount = 0; + p->fLastSideMoveSpeed = 0; + p->matchStrafeChangeCount = 0; + p->matchPerfectStrafeCount = 0; + p->totalStrafeChangeCount = 0; + p->totalPerfectStrafeCount = 0; + p->nullStrafeCount = 0; + } + for (p = world; (p = find_plr(p));) { if (!k_matchLess) diff --git a/src/stats.c b/src/stats.c index fbc018d6..889295f5 100644 --- a/src/stats.c +++ b/src/stats.c @@ -766,10 +766,11 @@ void OnePlayerStats(gedict_t *p, int tp) // movement if (!p->isBot) { - G_bprint(2, "%s: %s:%.1f%% (%d/%d) %s:%d/%d\n", redtext("Movement"), redtext("Perfect strafes"), + G_bprint(2, "%s: %s:%.1f%% (%d/%d) %s:%d/%d%s [%s]\n", redtext("Movement"), redtext("Perfect strafes"), p->matchStrafeChangeCount > 0 ? 100.0 * p->matchPerfectStrafeCount / p->matchStrafeChangeCount : 0.0, p->matchPerfectStrafeCount, p->matchStrafeChangeCount, redtext("SOCD detections"), - p->socdDetected, p->socdChecksCount); + p->socdDetectionCount, p->socdValidationCount, + socd_movement_assisted(p) ? ". SOCD movement assistance detected!" : "", SOCD_DETECTION_VERSION); } From 3cb53cfa490c150585a1e562a5fbfbc592ce8249 Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 14 Sep 2025 14:28:57 +0200 Subject: [PATCH 11/34] Preparing 1.46 release) --- include/g_local.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/g_local.h b/include/g_local.h index 699afc14..81d5910a 100644 --- a/include/g_local.h +++ b/include/g_local.h @@ -76,7 +76,7 @@ #define MOD_NAME ("KTX") #define MOD_FULLNAME ("KTX: Kombat Teams eXtreme") -#define MOD_VERSION ("1.46-dev") +#define MOD_VERSION ("1.46") #define MOD_BUILD_DATE (__DATE__ ", " __TIME__) #define MOD_SERVERINFO_MOD_KEY ("ktxver") #define MOD_URL ("https://github.com/QW-Group/ktx") From 44b1296d9abc8b8f6668b565fc0363ffd2593bcc Mon Sep 17 00:00:00 2001 From: Toma Date: Sun, 14 Sep 2025 21:06:42 +0200 Subject: [PATCH 12/34] starting 1.47-dev --- include/g_local.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/g_local.h b/include/g_local.h index 81d5910a..bcd5038d 100644 --- a/include/g_local.h +++ b/include/g_local.h @@ -76,7 +76,7 @@ #define MOD_NAME ("KTX") #define MOD_FULLNAME ("KTX: Kombat Teams eXtreme") -#define MOD_VERSION ("1.46") +#define MOD_VERSION ("1.47-dev") #define MOD_BUILD_DATE (__DATE__ ", " __TIME__) #define MOD_SERVERINFO_MOD_KEY ("ktxver") #define MOD_URL ("https://github.com/QW-Group/ktx") From eb35c93023d0a0991ec4b66666ceca2f7f60c30c Mon Sep 17 00:00:00 2001 From: "ESAAD\\Tamas.Csabina" Date: Sun, 14 Sep 2025 22:20:18 +0200 Subject: [PATCH 13/34] BUG FIX: relink after player solid state changes --- src/client.c | 7 ++++++- src/match.c | 6 ++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/client.c b/src/client.c index dbb76bca..c7c4e0ac 100644 --- a/src/client.c +++ b/src/client.c @@ -170,9 +170,11 @@ void CheckTiming(void) p->s.v.solid = 0; p->s.v.movetype = 0; SetVector(p->s.v.velocity, 0, 0, 0); // speed is zeroed and not restored + + // Relink after solid change to avoid stale area list membership + setorigin(p, PASSVEC3(p->s.v.origin)); } } - } else { @@ -3054,6 +3056,9 @@ void BackFromLag(void) self->s.v.takedamage = self->k_timingTakedmg; self->s.v.solid = self->k_timingSolid; self->s.v.movetype = self->k_timingMovetype; + + // Relink after solid change to ensure proper area list placement + setorigin(self, PASSVEC3(self->s.v.origin)); } } diff --git a/src/match.c b/src/match.c index 83c8823a..09863dd4 100644 --- a/src/match.c +++ b/src/match.c @@ -1909,6 +1909,9 @@ void standby_think(void) p->s.v.movetype = 0; p->s.v.modelindex = 0; p->model = ""; + + // Relink after solid change to keep area lists consistent + setorigin(p, PASSVEC3(p->s.v.origin)); } } } @@ -2440,6 +2443,9 @@ void StopTimer(int removeDemo) p->s.v.solid = SOLID_SLIDEBOX; p->s.v.movetype = MOVETYPE_WALK; setmodel(p, "progs/player.mdl"); + + // Relink after solid change so players are returned to the correct list + setorigin(p, PASSVEC3(p->s.v.origin)); } } From b0d83b0360b7f1dc0a5d5441ccafd65eb1d9cf09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Linus=20B=C3=A4ckman?= Date: Tue, 16 Sep 2025 20:43:05 +0200 Subject: [PATCH 14/34] Add bot support for map Catalyst --- .../ktx/bots/maps/catalyst.bot | 487 ++++++++++++++++++ 1 file changed, 487 insertions(+) create mode 100644 resources/example-configs/ktx/bots/maps/catalyst.bot diff --git a/resources/example-configs/ktx/bots/maps/catalyst.bot b/resources/example-configs/ktx/bots/maps/catalyst.bot new file mode 100644 index 00000000..da996653 --- /dev/null +++ b/resources/example-configs/ktx/bots/maps/catalyst.bot @@ -0,0 +1,487 @@ +CreateMarker 1454 142 -14 +CreateMarker 1347 186 -14 +CreateMarker 1473 18 -14 +CreateMarker 1468 -117 -14 +CreateMarker 1059 -283 50 +CreateMarker 1096 -121 18 +CreateMarker 1145 187 -14 +CreateMarker 1113 348 18 +CreateMarker 1027 413 18 +CreateMarker 800 295 18 +CreateMarker 451 272 50 +CreateMarker 359 323 50 +CreateMarker 288 167 50 +CreateMarker 288 47 50 +CreateMarker 615 -335 50 +CreateMarker 751 -412 50 +CreateMarker 1132 -399 50 +CreateMarker 619 -108 50 +CreateMarker 595 54 50 +CreateMarker 423 33 50 +CreateMarker 305 -289 256 +CreateMarker 479 -293 256 +CreateMarker 629 -203 256 +CreateMarker 44 -152 256 +CreateMarker -154 -154 256 +CreateMarker -208 -291 256 +CreateMarker 99 115 256 +CreateMarker 100 253 207 +CreateMarker 193 416 203 +CreateMarker 465 368 203 +CreateMarker 497 169 203 +CreateMarker 694 298 235 +CreateMarker 819 268 235 +CreateMarker 825 84 235 +CreateMarker 1008 283 235 +CreateMarker 1111 236 235 +CreateMarker 1265 224 184 +CreateMarker 1260 66 184 +CreateMarker 1443 59 184 +CreateMarker 1134 46 184 +CreateMarker 861 -198 235 +CreateMarker 1087 -308 235 +CreateMarker 1589 -365 -14 +CreateMarker 1007 -413 50 +CreateMarker 676 21 288 +CreateMarker 602 281 219 +CreateMarker 1260 66 -22 +CreateMarker 1133 60 -22 +CreateMarker 1259 206 -14 +CreateMarker 1207 -239 -22 +CreateMarker 1300 -240 -22 +CreateMarker 1410 -498 -22 +CreateMarker 1646 -527 -22 +CreateMarker 1376 -336 -22 +CreateMarker 1600 70 -22 +CreateMarker 1600 -103 -22 +CreateMarker 1625 -235 -22 +CreateMarker 1725 -272 -22 +CreateMarker 1234 304 -22 +CreateMarker 1364 304 -22 +CreateMarker 992 -16 -22 +CreateMarker 992 185 -22 +CreateMarker 993 262 -22 +SetZone 1 6 +SetMarkerPath 1 0 90 +SetMarkerPath 1 1 17 +SetMarkerPath 1 2 91 +SetZone 2 7 +SetMarkerPath 2 1 55 +SetMarkerPath 2 2 34 +SetMarkerPath 2 3 89 +SetZone 3 1 +SetMarkerPath 3 0 15 +SetMarkerPath 3 1 92 +SetZone 4 2 +SetMarkerPath 4 0 64 +SetMarkerPath 4 1 65 +SetZone 5 4 +SetMarkerPath 5 0 75 +SetMarkerPath 5 1 74 +SetMarkerPath 5 2 43 +SetZone 6 4 +SetMarkerPath 6 0 22 +SetMarkerPath 6 1 70 +SetZone 7 3 +SetMarkerPath 7 0 59 +SetMarkerPath 7 1 14 +SetGoal 8 1 +SetZone 8 6 +SetMarkerPath 8 0 91 +SetMarkerPath 8 1 34 +SetMarkerPath 8 2 53 +SetMarkerPath 8 3 55 +SetGoal 9 22 +SetZone 9 3 +SetMarkerPath 9 0 63 +SetMarkerPath 9 1 67 +SetMarkerPath 9 2 68 +SetMarkerPath 9 3 69 +SetGoal 10 2 +SetZone 10 1 +SetMarkerPath 10 0 50 +SetMarkerPath 10 1 51 +SetMarkerPath 10 2 52 +SetGoal 11 3 +SetZone 11 5 +SetMarkerPath 11 0 77 +SetMarkerPath 11 1 78 +SetMarkerPath 11 2 19 +SetMarkerPath 11 3 62 +SetMarkerPath 11 4 37 +SetGoal 12 4 +SetZone 12 2 +SetMarkerPath 12 0 65 +SetMarkerPath 12 1 93 +SetGoal 13 16 +SetZone 13 6 +SetMarkerPath 13 0 82 +SetMarkerPath 13 1 47 +SetGoal 14 5 +SetZone 14 3 +SetMarkerPath 14 0 59 +SetMarkerPath 14 1 68 +SetMarkerPath 14 2 69 +SetGoal 15 21 +SetZone 15 1 +SetMarkerPath 15 0 53 +SetMarkerPath 15 1 92 +SetGoal 16 6 +SetZone 16 7 +SetMarkerPath 16 0 84 +SetMarkerPath 16 1 85 +SetMarkerPath 16 2 87 +SetMarkerPath 16 3 89 +SetGoal 17 20 +SetZone 17 6 +SetMarkerPath 17 0 90 +SetMarkerPath 17 1 91 +SetMarkerPath 17 2 55 +SetMarkerPath 17 3 34 +SetGoal 18 16 +SetZone 18 3 +SetMarkerPath 18 0 19 +SetMarkerPath 18 1 63 +SetGoal 19 16 +SetZone 19 3 +SetMarkerPath 19 0 62 +SetMarkerPath 19 1 18 +SetGoal 20 16 +SetZone 20 2 +SetMarkerPath 20 0 66 +SetMarkerPath 20 1 21 +SetMarkerPath 20 2 54 +SetGoal 21 16 +SetZone 21 2 +SetMarkerPath 21 0 66 +SetMarkerPath 21 1 20 +SetMarkerPath 21 2 34 +SetMarkerPath 21 3 54 +SetGoal 22 17 +SetZone 22 4 +SetMarkerPath 22 0 70 +SetMarkerPath 22 1 73 +SetGoal 23 7 +SetZone 23 5 +SetMarkerPath 23 0 80 +SetMarkerPath 23 1 94 +SetMarkerPath 24 0 25 +SetMarkerPath 25 0 73 +SetMarkerPath 25 1 76 +SetZone 26 4 +SetMarkerPath 26 0 75 +SetMarkerPath 26 1 27 +SetZone 27 4 +SetMarkerPath 27 0 28 +SetZone 28 1 +SetMarkerPath 28 0 55 +SetMarkerPath 28 1 54 +SetZone 29 1 +SetMarkerPath 29 0 26 +SetMarkerPath 30 0 31 +SetZone 31 7 +SetMarkerPath 31 0 88 +SetMarkerPath 31 1 86 +SetMarkerPath 31 2 87 +SetGoal 32 19 +SetZone 32 1 +SetMarkerPath 32 0 57 +SetMarkerPath 32 1 33 +SetMarkerPath 32 2 58 +SetGoal 33 19 +SetZone 33 1 +SetMarkerPath 33 0 57 +SetMarkerPath 33 1 32 +SetMarkerPath 33 2 58 +SetGoal 34 18 +SetZone 34 1 +SetMarkerPath 34 0 55 +SetGoal 35 18 +SetZone 35 6 +SetMarkerPath 35 0 48 +SetMarkerPath 35 1 90 +SetGoal 36 18 +SetZone 36 3 +SetMarkerPath 36 0 67 +SetMarkerPath 36 1 64 +SetGoal 37 18 +SetZone 37 5 +SetMarkerPath 37 0 78 +SetMarkerPath 37 1 79 +SetMarkerPath 37 2 11 +SetGoal 38 23 +SetZone 38 7 +SetMarkerPath 38 0 84 +SetMarkerPath 38 1 39 +SetGoal 39 24 +SetZone 39 7 +SetMarkerPath 39 0 38 +SetMarkerPath 39 1 46 +SetGoal 40 23 +SetZone 40 3 +SetMarkerPath 40 0 68 +SetMarkerPath 40 1 45 +SetZone 41 2 +SetMarkerPath 41 0 70 +SetGoal 43 16 +SetZone 43 4 +SetMarkerPath 43 0 74 +SetGoal 44 19 +SetZone 44 4 +SetMarkerPath 44 0 71 +SetMarkerPath 44 1 72 +SetGoal 45 19 +SetZone 45 3 +SetMarkerPath 45 0 68 +SetMarkerPath 45 1 40 +SetMarkerPath 45 2 67 +SetGoal 46 16 +SetZone 46 7 +SetMarkerPath 46 0 39 +SetGoal 47 16 +SetZone 47 6 +SetMarkerPath 47 0 81 +SetMarkerPath 47 1 82 +SetMarkerPath 47 2 13 +SetGoal 48 8 +SetZone 48 6 +SetMarkerPath 48 0 83 +SetMarkerPath 48 1 35 +SetGoal 49 16 +SetZone 49 3 +SetMarkerPath 49 0 58 +SetMarkerPath 49 1 59 +SetZone 50 1 +SetMarkerPath 50 0 10 +SetMarkerPathFlags 50 0 j +SetMarkerPath 50 1 51 +SetMarkerPath 50 2 52 +SetZone 51 1 +SetMarkerPath 51 0 50 +SetMarkerPath 51 1 56 +SetMarkerPath 51 2 10 +SetMarkerPath 51 3 98 +SetZone 52 1 +SetMarkerPath 52 0 50 +SetMarkerPath 52 1 53 +SetMarkerPath 52 2 10 +SetZone 53 1 +SetMarkerPath 53 0 52 +SetMarkerPath 53 1 15 +SetZone 54 2 +SetMarkerPath 54 0 93 +SetMarkerPath 54 1 21 +SetMarkerPath 54 2 20 +SetMarkerPath 54 3 66 +SetMarkerPath 54 4 55 +SetZone 55 1 +SetMarkerPath 55 0 34 +SetMarkerPath 55 1 54 +SetZone 56 1 +SetMarkerPath 56 0 51 +SetMarkerPath 56 1 57 +SetMarkerPath 56 2 98 +SetZone 57 1 +SetMarkerPath 57 0 56 +SetMarkerPath 57 1 58 +SetMarkerPath 57 2 33 +SetMarkerPath 57 3 32 +SetZone 58 1 +SetMarkerPath 58 0 57 +SetMarkerPath 58 1 59 +SetMarkerPath 58 2 33 +SetMarkerPath 58 3 32 +SetMarkerPath 58 4 49 +SetZone 59 3 +SetMarkerPath 59 0 58 +SetMarkerPath 59 1 49 +SetMarkerPath 59 2 14 +SetZone 60 3 +SetZone 61 3 +SetMarkerPath 61 0 69 +SetMarkerPath 61 1 24 +SetZone 62 3 +SetMarkerPath 62 0 19 +SetMarkerPathFlags 62 0 j +SetMarkerPath 62 1 69 +SetZone 63 3 +SetMarkerPath 63 0 18 +SetMarkerPathFlags 63 0 j +SetMarkerPath 63 1 9 +SetMarkerPath 63 2 69 +SetZone 64 2 +SetMarkerPath 64 0 67 +SetMarkerPath 64 1 65 +SetMarkerPath 64 2 36 +SetZone 65 2 +SetMarkerPath 65 0 64 +SetMarkerPath 65 1 12 +SetZone 66 2 +SetMarkerPath 66 0 93 +SetMarkerPath 66 1 30 +SetMarkerPath 66 2 20 +SetMarkerPath 66 3 21 +SetMarkerPath 66 4 54 +SetZone 67 3 +SetMarkerPath 67 0 9 +SetMarkerPath 67 1 64 +SetMarkerPath 67 2 68 +SetMarkerPath 67 3 45 +SetMarkerPath 67 4 36 +SetZone 68 3 +SetMarkerPath 68 0 14 +SetMarkerPath 68 1 67 +SetMarkerPath 68 2 40 +SetMarkerPath 68 3 45 +SetMarkerPath 68 4 9 +SetMarkerPath 68 5 69 +SetZone 69 3 +SetMarkerPath 69 0 68 +SetMarkerPath 69 1 63 +SetMarkerPath 69 2 62 +SetMarkerPath 69 3 9 +SetMarkerPath 69 4 61 +SetMarkerPath 69 5 14 +SetZone 70 4 +SetMarkerPath 70 0 22 +SetMarkerPath 70 1 71 +SetMarkerPathFlags 70 1 j +SetZone 71 4 +SetMarkerPath 71 0 70 +SetMarkerPathFlags 71 0 j +SetMarkerPath 71 1 44 +SetZone 72 4 +SetMarkerPath 72 0 44 +SetMarkerPath 72 1 45 +SetMarkerPath 72 2 68 +SetMarkerPath 72 3 69 +SetMarkerPath 72 4 94 +SetZone 73 4 +SetMarkerPath 73 0 22 +SetMarkerPath 73 1 25 +SetMarkerPath 73 2 74 +SetZone 74 4 +SetMarkerPath 74 0 73 +SetMarkerPath 74 1 43 +SetMarkerPath 74 2 75 +SetZone 75 4 +SetMarkerPath 75 0 74 +SetMarkerPath 75 1 26 +SetMarkerPath 75 2 27 +SetZone 76 4 +SetMarkerPath 76 0 25 +SetMarkerPath 76 1 77 +SetZone 77 5 +SetMarkerPath 77 0 76 +SetMarkerPath 77 1 11 +SetMarkerPath 77 2 78 +SetZone 78 5 +SetMarkerPath 78 0 77 +SetMarkerPath 78 1 11 +SetMarkerPath 78 2 37 +SetMarkerPath 78 3 79 +SetZone 79 5 +SetMarkerPath 79 0 78 +SetMarkerPath 79 1 37 +SetMarkerPath 79 2 80 +SetMarkerPath 79 3 81 +SetMarkerPath 79 4 95 +SetZone 80 5 +SetMarkerPath 80 0 23 +SetMarkerPathFlags 80 0 r +SetRocketJumpPathFields 80 0 41.0 313.0 3 +SetMarkerPath 80 1 79 +SetMarkerPath 80 2 95 +SetZone 81 6 +SetMarkerPath 81 0 79 +SetMarkerPath 81 1 95 +SetMarkerPath 81 2 47 +SetMarkerPath 81 3 82 +SetZone 82 6 +SetMarkerPath 82 0 81 +SetMarkerPath 82 1 13 +SetMarkerPath 82 2 47 +SetMarkerPath 82 3 83 +SetMarkerPath 82 4 84 +SetZone 83 6 +SetMarkerPath 83 0 82 +SetMarkerPath 83 1 48 +SetZone 84 7 +SetMarkerPath 84 0 82 +SetMarkerPath 84 1 16 +SetMarkerPath 84 2 38 +SetZone 85 7 +SetMarkerPath 85 0 16 +SetMarkerPath 85 1 86 +SetZone 86 7 +SetMarkerPath 86 0 85 +SetMarkerPath 86 1 88 +SetMarkerPath 86 2 87 +SetZone 87 7 +SetMarkerPath 87 0 88 +SetMarkerPath 87 1 86 +SetMarkerPath 87 2 89 +SetZone 88 7 +SetMarkerPath 88 0 86 +SetMarkerPath 88 1 87 +SetZone 89 7 +SetMarkerPath 89 0 87 +SetZone 90 6 +SetMarkerPath 90 0 35 +SetMarkerPath 90 1 17 +SetZone 91 6 +SetMarkerPath 91 0 17 +SetMarkerPath 91 1 8 +SetMarkerPath 91 2 55 +SetMarkerPath 91 3 34 +SetZone 92 1 +SetMarkerPath 92 0 15 +SetMarkerPath 92 1 29 +SetZone 93 2 +SetMarkerPath 93 0 12 +SetMarkerPath 93 1 54 +SetMarkerPath 93 2 66 +SetZone 94 5 +SetMarkerPath 94 0 72 +SetMarkerPath 94 1 23 +SetZone 95 5 +SetMarkerPath 95 0 80 +SetMarkerPath 95 1 81 +SetMarkerPath 95 2 79 +SetZone 96 1 +SetMarkerPath 96 0 34 +SetMarkerPath 96 1 98 +SetZone 97 1 +SetMarkerPath 97 0 56 +SetZone 98 1 +SetMarkerPath 98 0 51 +SetMarkerPath 98 1 56 +SetZone 99 1 +SetZone 100 1 +SetMarkerPath 100 0 34 +SetZone 101 1 +SetMarkerPath 101 0 92 +SetZone 102 1 +SetMarkerPath 102 0 92 +SetZone 103 1 +SetMarkerPath 103 0 15 +SetZone 104 1 +SetMarkerPath 104 0 52 +SetZone 105 1 +SetMarkerPath 105 0 53 +SetZone 106 1 +SetMarkerPath 106 0 92 +SetMarkerPath 106 1 15 +SetZone 107 1 +SetMarkerPath 107 0 92 +SetMarkerPath 107 1 29 +SetZone 108 1 +SetMarkerPath 108 0 98 +SetZone 109 1 +SetMarkerPath 109 0 51 +SetZone 110 1 +SetMarkerPath 110 0 111 +SetZone 111 1 +SetMarkerPath 111 0 56 +SetZone 112 1 +SetMarkerPath 112 0 56 From f789d9f92af19b053a1aa0d6ec0e89cfc925c7b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Linus=20B=C3=A4ckman?= Date: Tue, 16 Sep 2025 20:43:19 +0200 Subject: [PATCH 15/34] Add bot support for map Stronghold --- .../ktx/bots/maps/stronghold.bot | 1123 +++++++++++++++++ 1 file changed, 1123 insertions(+) create mode 100644 resources/example-configs/ktx/bots/maps/stronghold.bot diff --git a/resources/example-configs/ktx/bots/maps/stronghold.bot b/resources/example-configs/ktx/bots/maps/stronghold.bot new file mode 100644 index 00000000..08c96210 --- /dev/null +++ b/resources/example-configs/ktx/bots/maps/stronghold.bot @@ -0,0 +1,1123 @@ +CreateMarker -4 1162 104 +CreateMarker -182 798 104 +CreateMarker -3 712 104 +CreateMarker -1 859 104 +CreateMarker -173 928 104 +CreateMarker 339 788 104 +CreateMarker 123 893 104 +CreateMarker 111 761 104 +CreateMarker -4 1014 424 +CreateMarker -74 504 424 +CreateMarker 77 496 424 +CreateMarker 5 502 424 +CreateMarker 5 321 24 +CreateMarker -1 396 24 +CreateMarker -140 363 24 +CreateMarker -299 -4 24 +CreateMarker -706 0 104 +CreateMarker -864 -10 104 +CreateMarker -1015 -124 104 +CreateMarker -1241 -167 104 +CreateMarker -1048 139 104 +CreateMarker -1251 171 104 +CreateMarker -1459 -154 184 +CreateMarker -1457 144 184 +CreateMarker -1595 2 184 +CreateMarker -1498 250 184 +CreateMarker -1390 318 184 +CreateMarker -1360 472 184 +CreateMarker -1273 319 187 +CreateMarker -1061 312 293 +CreateMarker -930 215 296 +CreateMarker -864 332 316 +CreateMarker -901 301 296 +CreateMarker -1549 159 184 +CreateMarker -908 -217 296 +CreateMarker -874 -319 311 +CreateMarker -780 -431 328 +CreateMarker -1114 -323 267 +CreateMarker -1263 -326 193 +CreateMarker -1418 -311 184 +CreateMarker -498 -700 326 +CreateMarker -387 -748 312 +CreateMarker -240 -687 312 +CreateMarker -45 -645 312 +CreateMarker -281 -1460 312 +CreateMarker 242 -742 312 +CreateMarker 287 -927 312 +CreateMarker 323 -1093 312 +CreateMarker 10 -331 328 +CreateMarker -80 -350 328 +CreateMarker 80 -347 328 +CreateMarker 600 -1113 152 +CreateMarker -644 -428 104 +CreateMarker -1303 590 184 +CreateMarker -1003 577 184 +CreateMarker -802 458 148 +CreateMarker -568 377 104 +CreateMarker -428 606 104 +CreateMarker -367 787 104 +CreateMarker 200 988 104 +CreateMarker 283 886 104 +CreateMarker 583 785 184 +CreateMarker 710 582 184 +CreateMarker 584 647 184 +CreateMarker 328 583 184 +CreateMarker 560 432 184 +CreateMarker 844 621 184 +CreateMarker 414 582 184 +CreateMarker 498 375 184 +CreateMarker 802 804 184 +CreateMarker 520 1067 184 +CreateMarker 664 1052 184 +CreateMarker 839 1034 184 +CreateMarker 1010 1016 184 +CreateMarker 1030 405 184 +CreateMarker 1036 539 184 +CreateMarker 1135 323 184 +CreateMarker 911 224 184 +CreateMarker 824 2 160 +CreateMarker 890 128 184 +CreateMarker 1184 5 160 +CreateMarker 1171 124 184 +CreateMarker 1152 195 184 +CreateMarker 1177 -98 177 +CreateMarker 887 -104 180 +CreateMarker 956 -258 184 +CreateMarker 1133 -257 184 +CreateMarker 1118 -377 184 +CreateMarker 1306 -293 184 +CreateMarker 1441 -199 184 +CreateMarker 1450 227 184 +CreateMarker 1299 280 184 +CreateMarker 1109 -538 152 +CreateMarker 1303 -582 184 +CreateMarker 1454 -645 184 +CreateMarker 1448 -846 184 +CreateMarker 1327 -917 184 +CreateMarker 1126 -930 152 +CreateMarker 984 -1031 152 +CreateMarker 917 -1214 152 +CreateMarker 893 -1369 152 +CreateMarker 724 -1414 152 +CreateMarker 594 -1388 152 +CreateMarker 608 -1263 152 +CreateMarker 731 -1095 152 +CreateMarker 877 -1059 152 +CreateMarker 577 -934 173 +CreateMarker 609 -785 232 +CreateMarker 727 -743 232 +CreateMarker 801 -595 232 +CreateMarker 701 -549 232 +CreateMarker 553 -657 232 +CreateMarker 484 -495 232 +CreateMarker 354 -362 24 +CreateMarker 210 -299 24 +CreateMarker 313 -211 24 +CreateMarker 13 -307 24 +CreateMarker -110 -242 24 +CreateMarker -316 -315 24 +CreateMarker -401 -399 24 +CreateMarker -222 -106 24 +CreateMarker 239 -102 24 +CreateMarker 239 58 24 +CreateMarker 134 314 24 +CreateMarker 0 499 24 +CreateMarker 220 174 24 +CreateMarker 5 152 31 +CreateMarker -195 84 24 +CreateMarker -8 -766 104 +CreateMarker -13 -930 104 +CreateMarker -123 -1028 104 +CreateMarker -125 -1194 104 +CreateMarker -386 -1006 184 +CreateMarker -357 -1130 184 +CreateMarker -386 -1530 248 +CreateMarker -400 -1290 195 +CreateMarker -8 -1284 104 +CreateMarker 194 -1500 104 +CreateMarker 504 -1479 152 +CreateMarker -391 -880 312 +CreateMarker 696 -1 328 +CreateMarker 626 -82 328 +CreateMarker 613 127 328 +CreateMarker 709 254 328 +CreateMarker 330 6 328 +CreateMarker 343 -80 328 +CreateMarker 353 80 328 +CreateMarker -271 -1288 312 +CreateMarker -158 -1463 312 +CreateMarker -276 -1359 312 +CreateMarker 0 -1415 312 +CreateMarker -8 -1483 312 +CreateMarker -6 1309 72 +CreateMarker -383 -944 184 +SetMarkerPath 1 0 4 +SetGoal 2 1 +SetZone 2 3 +SetMarkerPath 2 0 120 +SetMarkerPath 2 1 119 +SetMarkerPath 2 2 89 +SetMarkerPath 2 3 88 +SetMarkerPath 2 4 125 +SetMarkerPath 2 5 122 +SetGoal 3 2 +SetZone 3 7 +SetMarkerPath 3 0 149 +SetMarkerPath 3 1 153 +SetZone 4 1 +SetMarkerPath 4 0 118 +SetGoal 5 16 +SetZone 5 5 +SetMarkerPath 5 0 240 +SetMarkerPath 5 1 6 +SetMarkerPath 5 2 241 +SetMarkerPath 5 3 244 +SetGoal 6 16 +SetZone 6 5 +SetMarkerPath 6 0 240 +SetMarkerPath 6 1 5 +SetMarkerPath 6 2 241 +SetMarkerPath 6 3 244 +SetGoal 7 16 +SetZone 7 9 +SetMarkerPath 7 0 8 +SetMarkerPath 7 1 231 +SetGoal 8 16 +SetZone 8 9 +SetMarkerPath 8 0 229 +SetMarkerPath 8 1 7 +SetMarkerPath 8 2 230 +SetMarkerPath 8 3 91 +SetMarkerPath 8 4 231 +SetGoal 9 16 +SetZone 9 2 +SetMarkerPath 9 0 25 +SetMarkerPath 9 1 10 +SetGoal 10 16 +SetZone 10 2 +SetMarkerPath 10 0 9 +SetMarkerPath 10 1 67 +SetMarkerPath 10 2 194 +SetGoal 11 16 +SetZone 11 5 +SetMarkerPath 11 0 28 +SetMarkerPath 11 1 12 +SetMarkerPath 11 2 62 +SetGoal 12 16 +SetZone 12 5 +SetMarkerPath 12 0 28 +SetMarkerPath 12 1 11 +SetMarkerPath 12 2 62 +SetGoal 13 16 +SetZone 13 7 +SetMarkerPath 13 0 14 +SetMarkerPath 13 1 142 +SetMarkerPath 13 2 143 +SetGoal 14 16 +SetZone 14 7 +SetMarkerPath 14 0 141 +SetMarkerPath 14 1 13 +SetMarkerPath 14 2 143 +SetGoal 15 16 +SetZone 15 7 +SetMarkerPath 15 0 155 +SetMarkerPath 15 1 159 +SetGoal 16 24 +SetZone 16 8 +SetMarkerPath 16 0 17 +SetMarkerPath 16 1 166 +SetMarkerPath 16 2 255 +SetGoal 17 23 +SetZone 17 8 +SetMarkerPath 17 0 165 +SetMarkerPath 17 1 16 +SetMarkerPath 17 2 166 +SetMarkerPath 17 3 32 +SetGoal 18 18 +SetZone 18 6 +SetMarkerPath 18 0 95 +SetMarkerPath 18 1 172 +SetMarkerPath 18 2 146 +SetGoal 19 3 +SetZone 19 2 +SetMarkerPath 19 0 183 +SetMarkerPath 19 1 187 +SetGoal 20 18 +SetZone 20 1 +SetMarkerPath 20 0 259 +SetMarkerPath 20 1 261 +SetMarkerPath 20 2 30 +SetGoal 21 16 +SetZone 21 4 +SetMarkerPath 21 0 22 +SetMarkerPath 21 1 127 +SetGoal 22 16 +SetZone 22 4 +SetMarkerPath 22 0 127 +SetMarkerPath 22 1 21 +SetGoal 23 4 +SetZone 23 5 +SetMarkerPath 23 0 245 +SetMarkerPath 23 1 241 +SetMarkerPath 23 2 235 +SetMarkerPath 23 3 236 +SetMarkerPath 23 4 239 +SetGoal 24 24 +SetZone 24 2 +SetMarkerPath 24 0 188 +SetMarkerPath 24 1 25 +SetMarkerPath 24 2 192 +SetGoal 25 21 +SetZone 25 2 +SetMarkerPath 25 0 24 +SetMarkerPath 25 1 9 +SetMarkerPath 25 2 192 +SetGoal 26 5 +SetZone 26 1 +SetMarkerPath 26 0 198 +SetMarkerPath 26 1 200 +SetMarkerPath 26 2 199 +SetMarkerPath 26 3 202 +SetMarkerPath 26 4 197 +SetMarkerPath 26 5 203 +SetGoal 27 23 +SetZone 27 9 +SetMarkerPath 27 0 227 +SetMarkerPath 27 1 224 +SetMarkerPath 27 2 223 +SetMarkerPath 27 3 170 +SetGoal 28 17 +SetZone 28 5 +SetMarkerPath 28 0 238 +SetMarkerPath 28 1 11 +SetMarkerPath 28 2 12 +SetGoal 29 24 +SetZone 29 8 +SetMarkerPath 29 0 97 +SetMarkerPath 29 1 161 +SetMarkerPath 29 2 160 +SetMarkerPath 29 3 82 +SetGoal 30 16 +SetZone 30 1 +SetMarkerPath 30 0 260 +SetMarkerPath 30 1 31 +SetMarkerPath 30 2 20 +SetGoal 31 16 +SetZone 31 1 +SetMarkerPath 31 0 30 +SetMarkerPath 31 1 260 +SetGoal 32 20 +SetZone 32 8 +SetMarkerPath 32 0 248 +SetMarkerPath 32 1 250 +SetMarkerPath 32 2 249 +SetMarkerPath 32 3 255 +SetGoal 33 18 +SetZone 33 7 +SetMarkerPath 33 0 153 +SetMarkerPath 33 1 154 +SetGoal 34 16 +SetZone 34 5 +SetMarkerPath 34 0 12 +SetMarkerPath 34 1 28 +SetMarkerPath 34 2 171 +SetZone 35 14 +SetMarkerPath 35 0 231 +SetMarkerPath 36 0 21 +SetMarkerPath 36 1 22 +SetMarkerPath 37 0 259 +SetGoal 38 19 +SetZone 38 7 +SetMarkerPath 38 0 143 +SetMarkerPath 48 1 170 +SetZone 49 8 +SetMarkerPath 49 0 166 +SetMarkerPath 50 0 58 +SetZone 54 5 +SetMarkerPath 54 0 59 +SetMarkerPath 54 1 129 +SetMarkerPath 54 2 128 +SetMarkerPath 54 3 130 +SetZone 55 1 +SetGoal 56 6 +SetZone 56 6 +SetMarkerPath 56 0 172 +SetMarkerPath 56 1 173 +SetGoal 57 7 +SetZone 57 8 +SetMarkerPath 57 0 255 +SetMarkerPath 57 1 256 +SetGoal 58 18 +SetZone 58 8 +SetMarkerPath 58 0 161 +SetMarkerPath 58 1 162 +SetGoal 59 8 +SetZone 59 4 +SetMarkerPath 59 0 127 +SetZone 60 2 +SetMarkerPath 60 0 182 +SetMarkerPath 60 1 61 +SetMarkerPath 60 2 184 +SetMarkerPath 60 3 181 +SetMarkerPath 61 0 62 +SetZone 62 5 +SetMarkerPath 62 0 11 +SetMarkerPath 62 1 12 +SetMarkerPath 62 2 65 +SetZone 63 7 +SetMarkerPath 63 0 64 +SetZone 64 5 +SetMarkerPath 64 0 23 +SetMarkerPathFlags 64 0 j +SetZone 65 5 +SetMarkerPath 65 0 60 +SetGoal 66 19 +SetZone 66 9 +SetMarkerPath 66 0 213 +SetGoal 67 23 +SetZone 67 2 +SetMarkerPath 67 0 10 +SetMarkerPath 67 1 194 +SetGoal 68 23 +SetZone 68 7 +SetMarkerPath 68 0 143 +SetMarkerPath 69 0 20 +SetMarkerPath 69 1 263 +SetZone 70 5 +SetMarkerPath 70 0 58 +SetMarkerPath 70 1 167 +SetZone 71 5 +SetZone 72 7 +SetMarkerPath 72 0 134 +SetMarkerPath 72 1 107 +SetZone 74 3 +SetMarkerPath 76 0 235 +SetMarkerPath 76 1 247 +SetZone 77 5 +SetZone 80 3 +SetMarkerPath 80 0 124 +SetMarkerPath 80 1 180 +SetGoal 82 21 +SetZone 82 8 +SetMarkerPath 82 0 29 +SetMarkerPath 82 1 160 +SetMarkerPath 82 2 97 +SetMarkerPath 82 3 161 +SetMarkerPath 82 4 258 +SetGoal 83 16 +SetZone 83 5 +SetMarkerPath 83 0 133 +SetMarkerPath 83 1 84 +SetGoal 84 16 +SetZone 84 5 +SetMarkerPath 84 0 83 +SetMarkerPath 84 1 134 +SetGoal 85 20 +SetZone 85 6 +SetMarkerPath 85 0 176 +SetMarkerPath 85 1 86 +SetMarkerPath 85 2 175 +SetMarkerPath 85 3 87 +SetGoal 86 23 +SetZone 86 6 +SetMarkerPath 86 0 176 +SetMarkerPath 86 1 87 +SetMarkerPath 86 2 85 +SetGoal 87 23 +SetZone 87 6 +SetMarkerPath 87 0 176 +SetMarkerPath 87 1 86 +SetMarkerPath 87 2 85 +SetGoal 88 16 +SetZone 88 3 +SetMarkerPath 88 0 2 +SetMarkerPath 88 1 89 +SetGoal 89 16 +SetZone 89 3 +SetMarkerPath 89 0 2 +SetMarkerPath 89 1 88 +SetMarkerPath 89 2 178 +SetMarkerPath 90 0 258 +SetZone 91 9 +SetMarkerPath 91 0 92 +SetZone 92 9 +SetMarkerPath 92 0 106 +SetZone 93 9 +SetMarkerPath 93 0 95 +SetZone 94 9 +SetMarkerPath 94 0 106 +SetMarkerPath 94 1 93 +SetZone 95 6 +SetMarkerPath 95 0 146 +SetMarkerPath 95 1 96 +SetMarkerPath 95 2 18 +SetMarkerPath 95 3 172 +SetZone 96 6 +SetMarkerPath 96 0 94 +SetGoal 97 23 +SetZone 97 8 +SetMarkerPath 97 0 160 +SetMarkerPath 97 1 161 +SetMarkerPath 97 2 29 +SetMarkerPath 97 3 82 +SetGoal 98 16 +SetZone 98 1 +SetMarkerPath 98 0 208 +SetMarkerPath 98 1 209 +SetMarkerPath 98 2 1 +SetGoal 99 16 +SetZone 99 8 +SetMarkerPath 99 0 270 +SetMarkerPath 99 1 101 +SetMarkerPath 99 2 100 +SetGoal 100 16 +SetZone 100 8 +SetMarkerPath 100 0 270 +SetMarkerPath 100 1 101 +SetMarkerPath 100 2 99 +SetGoal 101 18 +SetZone 101 8 +SetMarkerPath 101 0 270 +SetMarkerPath 101 1 100 +SetMarkerPath 101 2 99 +SetGoal 106 9 +SetZone 106 9 +SetMarkerPath 106 0 92 +SetMarkerPath 106 1 94 +SetMarkerPath 106 2 27 +SetMarkerPath 106 3 216 +SetGoal 107 16 +SetZone 107 7 +SetMarkerPath 107 1 135 +SetZone 108 3 +SetMarkerPath 108 0 119 +SetMarkerPath 108 1 123 +SetMarkerPath 108 2 2 +SetZone 109 6 +SetMarkerPath 109 0 175 +SetMarkerPath 109 1 86 +SetMarkerPath 109 2 87 +SetMarkerPath 109 3 85 +SetMarkerPath 109 4 176 +SetZone 110 7 +SetMarkerPath 110 1 107 +SetMarkerPath 110 2 135 +SetZone 111 8 +SetMarkerPath 111 0 161 +SetMarkerPath 111 1 162 +SetMarkerPath 111 2 160 +SetZone 112 9 +SetMarkerPath 112 0 221 +SetMarkerPath 112 1 222 +SetMarkerPath 112 2 220 +SetMarkerPath 112 3 257 +SetZone 113 1 +SetMarkerPath 113 0 98 +SetMarkerPath 113 1 199 +SetZone 114 2 +SetMarkerPath 114 0 9 +SetMarkerPath 114 1 25 +SetMarkerPath 114 2 192 +SetZone 115 5 +SetMarkerPath 115 0 171 +SetGoal 116 10 +SetZone 116 2 +SetMarkerPath 116 0 9 +SetMarkerPath 116 1 10 +SetMarkerPath 116 2 25 +SetMarkerPath 116 3 194 +SetMarkerPath 116 4 185 +SetMarkerPath 116 5 188 +SetGoal 117 15 +SetZone 117 7 +SetMarkerPath 117 0 136 +SetMarkerPath 117 1 63 +SetMarkerPath 117 2 140 +SetMarkerPath 117 3 138 +SetGoal 118 11 +SetZone 118 1 +SetMarkerPath 118 0 259 +SetZone 119 3 +SetMarkerPath 119 0 2 +SetMarkerPath 119 1 36 +SetZone 120 3 +SetMarkerPath 120 0 123 +SetMarkerPath 120 1 2 +SetMarkerPath 120 2 122 +SetMarkerPath 120 3 121 +SetMarkerPath 120 4 177 +SetZone 121 3 +SetMarkerPath 121 0 126 +SetMarkerPath 121 1 122 +SetMarkerPath 121 2 120 +SetMarkerPath 121 4 243 +SetZone 122 3 +SetMarkerPath 122 0 2 +SetMarkerPath 122 1 121 +SetMarkerPath 122 2 126 +SetMarkerPath 122 3 120 +SetZone 123 3 +SetMarkerPath 123 0 120 +SetZone 124 3 +SetMarkerPath 124 0 126 +SetMarkerPath 124 1 125 +SetMarkerPath 124 2 179 +SetZone 125 3 +SetMarkerPath 125 0 124 +SetMarkerPath 125 1 2 +SetZone 126 3 +SetMarkerPath 126 0 121 +SetMarkerPath 126 1 124 +SetMarkerPath 126 2 122 +SetZone 127 4 +SetMarkerPath 127 0 22 +SetMarkerPath 127 1 21 +SetMarkerPath 127 2 59 +SetZone 128 5 +SetMarkerPath 128 1 129 +SetMarkerPath 128 2 130 +SetZone 129 5 +SetMarkerPath 129 1 128 +SetMarkerPath 129 2 130 +SetZone 130 5 +SetMarkerPath 130 0 128 +SetMarkerPath 130 1 129 +SetMarkerPath 130 3 131 +SetZone 131 5 +SetMarkerPath 131 0 132 +SetMarkerPath 131 1 245 +SetMarkerPath 131 2 133 +SetMarkerPath 131 3 242 +SetZone 132 5 +SetMarkerPath 132 1 131 +SetMarkerPath 132 2 133 +SetMarkerPath 132 4 243 +SetZone 133 5 +SetMarkerPath 133 0 132 +SetMarkerPath 133 1 83 +SetMarkerPath 133 2 243 +SetMarkerPath 133 3 131 +SetZone 134 5 +SetMarkerPath 134 0 84 +SetMarkerPath 134 2 239 +SetMarkerPath 134 3 246 +SetZone 135 7 +SetMarkerPath 135 0 136 +SetMarkerPath 135 1 107 +SetZone 136 7 +SetMarkerPath 136 0 135 +SetMarkerPath 136 1 137 +SetMarkerPath 136 2 117 +SetMarkerPath 136 3 139 +SetZone 137 7 +SetMarkerPath 137 0 136 +SetZone 138 7 +SetMarkerPath 138 0 117 +SetMarkerPath 138 1 141 +SetZone 139 7 +SetMarkerPath 139 0 136 +SetMarkerPath 139 1 140 +SetZone 140 7 +SetMarkerPath 140 0 139 +SetMarkerPath 140 1 117 +SetMarkerPath 140 2 142 +SetZone 141 7 +SetMarkerPath 141 0 138 +SetMarkerPath 141 1 14 +SetMarkerPath 141 2 143 +SetMarkerPath 141 3 158 +SetZone 142 7 +SetMarkerPath 142 0 13 +SetMarkerPath 142 1 140 +SetMarkerPath 142 2 143 +SetMarkerPath 142 3 144 +SetMarkerPath 142 4 152 +SetZone 143 7 +SetMarkerPath 143 0 14 +SetMarkerPath 143 1 13 +SetMarkerPath 143 2 38 +SetMarkerPath 143 3 68 +SetMarkerPath 143 4 142 +SetMarkerPath 143 5 141 +SetMarkerPath 143 6 152 +SetZone 144 7 +SetMarkerPath 144 0 142 +SetMarkerPath 144 1 152 +SetMarkerPath 144 2 145 +SetZone 145 7 +SetMarkerPath 145 0 144 +SetMarkerPath 145 1 146 +SetMarkerPath 145 2 147 +SetZone 146 6 +SetMarkerPath 146 0 145 +SetMarkerPath 146 1 95 +SetMarkerPath 146 2 172 +SetMarkerPath 146 3 18 +SetZone 147 7 +SetMarkerPath 147 0 145 +SetMarkerPath 147 1 148 +SetZone 148 7 +SetMarkerPath 148 0 147 +SetMarkerPath 148 1 149 +SetMarkerPath 148 2 151 +SetZone 149 7 +SetMarkerPath 149 0 148 +SetMarkerPath 149 1 151 +SetMarkerPath 149 2 3 +SetZone 150 7 +SetMarkerPath 150 0 151 +SetMarkerPath 150 1 174 +SetZone 151 7 +SetMarkerPath 151 0 148 +SetMarkerPath 151 1 150 +SetMarkerPathFlags 151 1 j +SetMarkerPath 151 2 149 +SetZone 152 7 +SetMarkerPath 152 0 143 +SetMarkerPath 152 1 144 +SetMarkerPath 152 2 142 +SetZone 153 7 +SetMarkerPath 153 0 3 +SetMarkerPath 153 1 154 +SetMarkerPath 153 2 33 +SetZone 154 7 +SetMarkerPath 154 0 153 +SetMarkerPath 154 1 33 +SetMarkerPath 154 2 156 +SetMarkerPath 154 3 155 +SetZone 155 7 +SetMarkerPath 155 0 154 +SetMarkerPath 155 1 15 +SetMarkerPath 155 2 34 +SetZone 156 7 +SetMarkerPath 156 0 157 +SetMarkerPath 156 1 154 +SetZone 157 7 +SetMarkerPath 157 0 158 +SetMarkerPath 157 1 156 +SetZone 158 7 +SetMarkerPath 158 0 141 +SetMarkerPath 158 1 157 +SetZone 159 8 +SetMarkerPath 159 0 15 +SetMarkerPath 159 1 160 +SetMarkerPath 159 2 258 +SetZone 160 8 +SetMarkerPath 160 0 159 +SetMarkerPath 160 1 97 +SetMarkerPath 160 2 29 +SetMarkerPath 160 3 82 +SetMarkerPath 160 4 258 +SetZone 161 8 +SetMarkerPath 161 0 97 +SetMarkerPath 161 1 29 +SetMarkerPath 161 2 82 +SetMarkerPath 161 3 162 +SetMarkerPath 161 4 58 +SetZone 162 8 +SetMarkerPath 162 0 161 +SetMarkerPath 162 1 58 +SetMarkerPath 162 3 248 +SetZone 163 8 +SetMarkerPath 163 0 267 +SetMarkerPath 163 1 268 +SetMarkerPath 163 2 253 +SetMarkerPath 163 3 254 +SetZone 164 8 +SetMarkerPath 164 1 165 +SetZone 165 8 +SetMarkerPath 165 0 164 +SetMarkerPath 165 1 166 +SetMarkerPath 165 2 17 +SetZone 166 8 +SetMarkerPath 166 0 165 +SetMarkerPath 166 1 16 +SetMarkerPath 166 2 17 +SetZone 167 5 +SetMarkerPath 167 1 169 +SetMarkerPath 167 2 168 +SetMarkerPath 167 3 23 +SetMarkerPathFlags 167 3 j +SetZone 168 5 +SetMarkerPath 168 0 167 +SetZone 169 5 +SetMarkerPath 169 0 167 +SetZone 170 9 +SetMarkerPath 170 0 222 +SetMarkerPath 170 1 223 +SetMarkerPath 170 2 225 +SetZone 171 5 +SetMarkerPath 171 0 34 +SetMarkerPath 171 1 12 +SetMarkerPath 171 2 28 +SetZone 172 6 +SetMarkerPath 172 0 95 +SetMarkerPath 172 1 146 +SetMarkerPath 172 2 56 +SetMarkerPath 172 3 18 +SetZone 173 6 +SetMarkerPath 173 0 174 +SetMarkerPath 173 1 56 +SetZone 174 6 +SetMarkerPath 174 0 175 +SetMarkerPath 174 1 173 +SetZone 175 6 +SetMarkerPath 175 0 174 +SetMarkerPath 175 1 176 +SetMarkerPath 175 2 85 +SetZone 176 6 +SetMarkerPath 176 0 87 +SetMarkerPath 176 1 86 +SetMarkerPath 176 2 85 +SetMarkerPath 176 3 175 +SetMarkerPath 176 4 177 +SetZone 177 6 +SetMarkerPath 177 0 176 +SetMarkerPath 177 1 120 +SetZone 178 3 +SetMarkerPath 178 0 89 +SetMarkerPath 178 1 179 +SetZone 179 3 +SetMarkerPath 179 0 178 +SetMarkerPath 179 1 124 +SetZone 180 2 +SetMarkerPath 180 1 182 +SetZone 181 2 +SetMarkerPath 181 0 184 +SetMarkerPath 181 1 182 +SetMarkerPath 181 2 60 +SetMarkerPath 181 3 185 +SetZone 182 2 +SetMarkerPath 182 0 180 +SetMarkerPath 182 1 60 +SetMarkerPath 182 2 186 +SetMarkerPath 182 3 181 +SetZone 183 2 +SetMarkerPath 183 0 186 +SetMarkerPath 183 1 19 +SetZone 184 2 +SetMarkerPath 184 0 187 +SetMarkerPath 184 1 60 +SetMarkerPath 184 2 181 +SetZone 185 2 +SetMarkerPath 185 0 194 +SetMarkerPath 185 1 181 +SetMarkerPath 185 2 188 +SetZone 186 2 +SetMarkerPath 186 0 182 +SetMarkerPath 186 1 183 +SetZone 187 2 +SetMarkerPath 187 0 19 +SetMarkerPath 187 1 184 +SetZone 188 2 +SetMarkerPath 188 0 185 +SetMarkerPath 188 1 24 +SetMarkerPath 188 2 191 +SetZone 189 2 +SetMarkerPath 189 0 190 +SetZone 190 2 +SetMarkerPath 190 0 191 +SetZone 191 2 +SetMarkerPath 191 0 192 +SetMarkerPath 191 1 188 +SetZone 192 2 +SetMarkerPath 192 0 191 +SetMarkerPath 192 1 24 +SetMarkerPath 192 2 25 +SetZone 193 1 +SetMarkerPath 193 0 194 +SetMarkerPath 193 1 196 +SetMarkerPath 193 2 195 +SetMarkerPath 193 3 201 +SetZone 194 2 +SetMarkerPath 194 0 185 +SetMarkerPath 194 1 67 +SetMarkerPath 194 2 10 +SetMarkerPath 194 3 193 +SetZone 195 1 +SetMarkerPath 195 0 193 +SetMarkerPath 195 1 210 +SetZone 196 1 +SetMarkerPath 196 0 193 +SetMarkerPath 196 1 198 +SetZone 197 1 +SetMarkerPath 197 0 198 +SetMarkerPath 197 1 26 +SetMarkerPath 197 2 203 +SetMarkerPath 197 3 37 +SetZone 198 1 +SetMarkerPath 198 0 196 +SetMarkerPath 198 1 26 +SetMarkerPath 198 2 197 +SetZone 199 1 +SetMarkerPath 199 0 200 +SetMarkerPath 199 1 26 +SetMarkerPath 199 2 202 +SetZone 200 1 +SetMarkerPath 200 0 201 +SetMarkerPath 200 1 199 +SetMarkerPath 200 2 26 +SetMarkerPath 200 3 210 +SetZone 201 1 +SetMarkerPath 201 0 193 +SetMarkerPath 201 1 200 +SetZone 202 1 +SetMarkerPath 202 0 199 +SetMarkerPath 202 1 26 +SetZone 203 1 +SetMarkerPath 203 0 26 +SetMarkerPath 203 1 204 +SetMarkerPath 203 2 197 +SetZone 204 1 +SetMarkerPath 204 0 203 +SetMarkerPath 204 1 205 +SetMarkerPath 204 2 206 +SetZone 205 1 +SetMarkerPath 205 0 204 +SetMarkerPath 205 1 206 +SetZone 206 1 +SetMarkerPath 206 0 204 +SetMarkerPath 206 1 205 +SetMarkerPath 206 2 207 +SetMarkerPath 206 3 211 +SetZone 207 1 +SetMarkerPath 207 0 206 +SetMarkerPath 207 1 208 +SetZone 208 1 +SetMarkerPath 208 0 207 +SetMarkerPath 208 1 98 +SetZone 209 1 +SetMarkerPath 209 0 98 +SetMarkerPath 209 1 210 +SetZone 210 1 +SetMarkerPath 210 0 209 +SetMarkerPath 210 1 200 +SetMarkerPath 210 3 195 +SetZone 211 9 +SetMarkerPath 211 0 206 +SetMarkerPath 211 1 212 +SetZone 212 9 +SetMarkerPath 212 0 211 +SetMarkerPath 212 1 213 +SetZone 213 9 +SetMarkerPath 213 0 212 +SetMarkerPath 213 1 66 +SetMarkerPath 213 2 214 +SetZone 214 9 +SetMarkerPath 214 0 213 +SetMarkerPath 214 1 215 +SetZone 215 9 +SetMarkerPath 215 0 214 +SetMarkerPath 215 1 216 +SetZone 216 9 +SetMarkerPath 216 0 215 +SetMarkerPath 216 1 217 +SetZone 217 9 +SetMarkerPath 217 0 216 +SetMarkerPath 217 1 218 +SetMarkerPath 217 2 224 +SetZone 218 9 +SetMarkerPath 218 0 217 +SetMarkerPath 218 1 219 +SetMarkerPath 218 2 224 +SetZone 219 9 +SetMarkerPath 219 0 218 +SetMarkerPath 219 1 220 +SetZone 220 9 +SetMarkerPath 220 0 219 +SetMarkerPath 220 1 221 +SetMarkerPath 220 2 222 +SetZone 221 9 +SetMarkerPath 221 0 257 +SetMarkerPath 221 1 222 +SetMarkerPath 221 2 220 +SetZone 222 9 +SetMarkerPath 222 0 221 +SetMarkerPath 222 1 220 +SetMarkerPath 222 2 170 +SetMarkerPath 222 3 223 +SetZone 223 9 +SetMarkerPath 223 0 224 +SetMarkerPath 223 1 170 +SetMarkerPath 223 2 222 +SetZone 224 9 +SetMarkerPath 224 0 217 +SetMarkerPath 224 1 218 +SetMarkerPath 224 2 223 +SetZone 225 9 +SetMarkerPath 225 0 170 +SetMarkerPath 225 1 226 +SetZone 226 9 +SetMarkerPath 226 0 225 +SetMarkerPath 226 1 227 +SetMarkerPath 226 2 230 +SetZone 227 9 +SetMarkerPath 227 0 226 +SetMarkerPath 227 1 91 +SetMarkerPath 227 2 27 +SetMarkerPath 227 3 228 +SetZone 228 9 +SetMarkerPath 228 0 227 +SetMarkerPath 228 1 229 +SetZone 229 9 +SetMarkerPath 229 0 230 +SetMarkerPath 229 1 8 +SetMarkerPath 229 2 228 +SetZone 230 9 +SetMarkerPath 230 0 226 +SetMarkerPath 230 1 91 +SetMarkerPath 230 2 229 +SetMarkerPath 230 3 8 +SetZone 231 9 +SetMarkerPath 231 0 7 +SetMarkerPath 231 1 8 +SetZone 232 5 +SetMarkerPath 232 0 35 +SetMarkerPath 232 1 234 +SetMarkerPath 232 2 233 +SetZone 233 5 +SetMarkerPath 233 0 232 +SetMarkerPath 233 1 235 +SetMarkerPath 233 2 240 +SetZone 234 5 +SetMarkerPath 234 0 232 +SetMarkerPath 234 1 240 +SetZone 235 5 +SetMarkerPath 235 0 233 +SetMarkerPath 235 1 236 +SetMarkerPath 235 2 240 +SetZone 236 5 +SetMarkerPath 236 0 235 +SetMarkerPath 236 1 237 +SetMarkerPath 236 2 239 +SetZone 237 5 +SetMarkerPath 237 0 236 +SetMarkerPath 237 1 238 +SetZone 238 5 +SetMarkerPath 238 0 237 +SetMarkerPath 238 1 28 +SetZone 239 5 +SetMarkerPath 239 0 236 +SetMarkerPath 239 1 134 +SetZone 240 5 +SetMarkerPath 240 0 241 +SetMarkerPath 240 1 234 +SetMarkerPath 240 2 233 +SetMarkerPath 240 3 235 +SetMarkerPath 240 4 6 +SetMarkerPath 240 5 5 +SetZone 241 5 +SetMarkerPath 241 0 244 +SetMarkerPath 241 1 240 +SetMarkerPath 241 2 6 +SetMarkerPath 241 3 5 +SetZone 242 5 +SetMarkerPath 242 0 243 +SetMarkerPath 242 1 244 +SetMarkerPath 242 2 131 +SetZone 243 5 +SetMarkerPath 243 0 132 +SetMarkerPath 243 1 121 +SetMarkerPath 243 2 133 +SetMarkerPath 243 3 242 +SetZone 244 5 +SetMarkerPath 244 0 242 +SetMarkerPath 244 1 241 +SetMarkerPath 244 2 5 +SetMarkerPath 244 3 6 +SetMarkerPath 244 4 245 +SetZone 245 5 +SetMarkerPath 245 0 244 +SetMarkerPath 245 1 246 +SetMarkerPath 245 2 131 +SetZone 246 5 +SetMarkerPath 246 0 245 +SetMarkerPath 246 1 134 +SetZone 247 8 +SetMarkerPath 247 1 248 +SetZone 248 8 +SetMarkerPath 248 0 247 +SetMarkerPath 248 1 249 +SetMarkerPath 248 2 32 +SetZone 249 8 +SetMarkerPath 249 0 248 +SetMarkerPath 249 1 32 +SetMarkerPath 249 2 252 +SetZone 250 8 +SetMarkerPath 250 0 32 +SetMarkerPath 250 1 255 +SetMarkerPath 250 2 252 +SetZone 251 8 +SetMarkerPath 251 0 252 +SetMarkerPath 251 1 90 +SetZone 252 8 +SetMarkerPath 252 0 250 +SetMarkerPath 252 1 249 +SetMarkerPath 252 2 254 +SetMarkerPath 252 3 251 +SetZone 253 8 +SetMarkerPath 253 0 254 +SetZone 254 8 +SetMarkerPath 254 0 252 +SetMarkerPath 254 1 253 +SetZone 255 8 +SetMarkerPath 255 0 32 +SetMarkerPath 255 1 250 +SetMarkerPath 255 2 57 +SetZone 256 8 +SetMarkerPath 256 0 257 +SetMarkerPath 256 1 57 +SetZone 257 9 +SetMarkerPath 257 0 221 +SetMarkerPath 257 1 256 +SetZone 258 8 +SetMarkerPath 258 0 82 +SetMarkerPath 258 1 160 +SetMarkerPath 258 2 159 +SetZone 259 1 +SetMarkerPath 259 0 20 +SetMarkerPath 259 1 261 +SetMarkerPath 259 2 260 +SetZone 260 1 +SetMarkerPath 260 0 259 +SetMarkerPath 260 1 30 +SetMarkerPath 260 2 31 +SetZone 261 1 +SetMarkerPath 261 0 262 +SetMarkerPath 261 1 259 +SetMarkerPath 261 2 20 +SetZone 262 1 +SetMarkerPath 262 0 261 +SetZone 263 5 +SetMarkerPath 263 1 264 +SetMarkerPath 263 2 265 +SetMarkerPath 263 3 23 +SetMarkerPathFlags 263 3 j +SetZone 264 5 +SetMarkerPath 264 0 263 +SetZone 265 5 +SetMarkerPath 265 0 263 +SetZone 266 8 +SetMarkerPath 266 0 268 +SetMarkerPath 266 1 252 +SetMarkerPath 266 2 250 +SetZone 267 8 +SetMarkerPath 267 0 270 +SetMarkerPath 267 1 163 +SetZone 268 8 +SetMarkerPath 268 0 163 +SetMarkerPath 268 1 266 +SetZone 269 8 +SetMarkerPath 269 0 270 +SetZone 270 8 +SetMarkerPath 270 0 99 +SetMarkerPath 270 1 100 +SetMarkerPath 270 2 101 +SetMarkerPath 270 3 269 +SetMarkerPath 270 4 267 +SetZone 271 3 +SetMarkerPath 271 0 119 +SetMarkerPathFlags 271 0 j +SetZone 272 8 +SetMarkerPath 272 0 251 From f622f533f4898aa836b393a05b7ad5d2e5374680 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Linus=20B=C3=A4ckman?= Date: Tue, 16 Sep 2025 20:43:33 +0200 Subject: [PATCH 16/34] Add bot support for map Defer --- .../example-configs/ktx/bots/maps/defer.bot | 1186 +++++++++++++++++ 1 file changed, 1186 insertions(+) create mode 100644 resources/example-configs/ktx/bots/maps/defer.bot diff --git a/resources/example-configs/ktx/bots/maps/defer.bot b/resources/example-configs/ktx/bots/maps/defer.bot new file mode 100644 index 00000000..ff165c19 --- /dev/null +++ b/resources/example-configs/ktx/bots/maps/defer.bot @@ -0,0 +1,1186 @@ +CreateMarker 381 339 -152 +CreateMarker 169 285 -104 +CreateMarker 50 316 -104 +CreateMarker -121 468 -40 +CreateMarker -208 358 -40 +CreateMarker -213 305 -3 +CreateMarker -168 68 -8 +CreateMarker -5 72 -8 +CreateMarker -212 -60 -8 +CreateMarker -206 -203 -8 +CreateMarker -109 -372 -8 +CreateMarker -203 -305 -8 +CreateMarker -315 298 -8 +CreateMarker -317 437 -8 +CreateMarker -18 610 -8 +CreateMarker 96 623 17 +CreateMarker 277 627 40 +CreateMarker 237 454 40 +CreateMarker 347 460 40 +CreateMarker 395 673 40 +CreateMarker 566 672 40 +CreateMarker 653 678 72 +CreateMarker 792 677 72 +CreateMarker 857 541 72 +CreateMarker 872 411 72 +CreateMarker 867 276 72 +CreateMarker 964 173 88 +CreateMarker 1066 -14 88 +CreateMarker 1166 103 88 +CreateMarker 1316 -3 88 +CreateMarker 1377 64 88 +CreateMarker 1186 -2 88 +CreateMarker 1348 329 104 +CreateMarker 1339 228 88 +CreateMarker 1021 123 88 +CreateMarker 993 -107 88 +CreateMarker 901 -193 88 +CreateMarker 791 -314 88 +CreateMarker 780 -124 88 +CreateMarker 634 -147 88 +CreateMarker 521 -253 88 +CreateMarker 660 -369 88 +CreateMarker 763 -486 88 +CreateMarker 913 -647 88 +CreateMarker 848 -776 88 +CreateMarker 839 -577 88 +CreateMarker 461 22 104 +CreateMarker 1016 668 72 +CreateMarker 951 769 72 +CreateMarker 945 892 72 +CreateMarker 1022 994 72 +CreateMarker 1214 1025 72 +CreateMarker 1484 1027 40 +CreateMarker 1627 1021 40 +CreateMarker 1762 1031 40 +CreateMarker 1917 1122 40 +CreateMarker 1910 1335 40 +CreateMarker 1825 1469 40 +CreateMarker 1525 1573 40 +CreateMarker 1517 1744 88 +CreateMarker 1505 1888 88 +CreateMarker 1316 2022 88 +CreateMarker 1335 1519 40 +CreateMarker 1180 1520 40 +CreateMarker 1116 1670 40 +CreateMarker 986 1636 40 +CreateMarker 1475 1405 40 +CreateMarker 962 1437 40 +CreateMarker 1273 1683 -216 +CreateMarker 1076 1594 -216 +CreateMarker 933 1584 -216 +CreateMarker 1244 1550 -216 +CreateMarker 722 1468 -184 +CreateMarker 719 1297 -184 +CreateMarker 685 1175 -184 +CreateMarker 568 1069 -184 +CreateMarker 445 938 -152 +CreateMarker 367 795 -152 +CreateMarker 359 581 -152 +CreateMarker 355 454 -152 +CreateMarker 357 134 -152 +CreateMarker 287 33 -152 +CreateMarker 195 -88 -152 +CreateMarker 80 -179 -152 +CreateMarker 307 277 -152 +CreateMarker 483 317 -152 +CreateMarker 622 318 -152 +CreateMarker 770 400 -152 +CreateMarker 746 230 -152 +CreateMarker 757 48 -184 +CreateMarker 757 -51 -184 +CreateMarker 612 -229 -184 +CreateMarker 607 -316 -184 +CreateMarker 774 -495 -216 +CreateMarker 995 -592 -216 +CreateMarker 1083 -514 -216 +CreateMarker 775 540 -152 +CreateMarker 807 670 -152 +CreateMarker 966 676 -152 +CreateMarker 1080 670 -152 +CreateMarker 1189 807 -152 +CreateMarker 1288 963 -152 +CreateMarker 1396 829 -152 +CreateMarker 1525 667 -152 +CreateMarker 1411 501 -152 +CreateMarker 1340 390 -152 +CreateMarker 1177 563 -152 +CreateMarker 1340 192 -214 +CreateMarker 1341 53 -216 +CreateMarker 1345 -80 -216 +CreateMarker 1456 -50 -216 +CreateMarker 1334 -270 -216 +CreateMarker 1186 -406 -216 +CreateMarker 1467 -370 -216 +CreateMarker 1539 -436 -216 +CreateMarker 1639 -532 -168 +CreateMarker 1787 -556 -168 +CreateMarker 1714 -649 -168 +CreateMarker 845 -566 -216 +CreateMarker 945 -740 -216 +CreateMarker 959 -880 -168 +CreateMarker 957 -994 -163 +CreateMarker 999 -1123 -168 +CreateMarker 1129 -1218 -168 +CreateMarker 1274 -505 -216 +CreateMarker 1635 -768 -168 +CreateMarker 1429 -925 -216 +CreateMarker 1340 -841 -265 +CreateMarker 1042 -754 -216 +CreateMarker 1269 -1123 -168 +CreateMarker 1646 683 -152 +CreateMarker 1823 678 -152 +CreateMarker 1964 670 -184 +CreateMarker 1808 814 -152 +CreateMarker 2180 663 40 +CreateMarker 2174 509 40 +CreateMarker 1996 430 40 +CreateMarker 1808 531 40 +CreateMarker 1891 453 40 +CreateMarker 1704 534 98 +CreateMarker 1679 665 120 +CreateMarker 1769 803 40 +CreateMarker 1949 890 40 +CreateMarker 2085 866 40 +CreateMarker 2179 752 40 +CreateMarker 2316 651 40 +CreateMarker 2488 642 40 +CreateMarker 2599 561 40 +CreateMarker 1289 1044 -152 +CreateMarker 1290 1210 -184 +CreateMarker 1400 1245 -184 +CreateMarker 1436 1352 -184 +CreateMarker 1163 1239 -184 +CreateMarker 1233 1413 -216 +CreateMarker 940 1439 -216 +CreateMarker 984 1284 -216 +CreateMarker 1406 947 40 +CreateMarker 1365 1032 40 +CreateMarker 1917 -437 -168 +CreateMarker 2089 -396 -168 +CreateMarker 2176 -393 -168 +CreateMarker 2380 -483 -248 +CreateMarker 2378 -274 -248 +CreateMarker 2222 -272 -216 +CreateMarker 2099 -164 -216 +CreateMarker 2602 -223 -248 +CreateMarker 2593 -12 -248 +CreateMarker 2302 13 -248 +CreateMarker 2266 35 -216 +CreateMarker 2460 -102 -248 +CreateMarker 2133 -12 -216 +CreateMarker 1237 1298 232 +CreateMarker 1272 1946 88 +CreateMarker -28 60 -147 +CreateMarker 58 152 -143 +CreateMarker 201 147 -154 +CreateMarker 81 -44 -152 +CreateMarker 1432 952 -112 +CreateMarker 1480 904 -72 +CreateMarker 1084 924 -152 +CreateMarker 1109 438 -152 +CreateMarker 927 -207 -216 +CreateMarker 845 -127 -184 +CreateMarker 730 -162 -184 +CreateMarker 1292 -717 -260 +CreateMarker 1223 -790 -267 +CreateMarker -42 170 -32 +CreateMarker 1322 1892 -24 +CreateMarker 1220 1890 -25 +SetMarkerPath 1 0 37 +SetMarkerPath 2 0 35 +SetZone 4 3 +SetMarkerPath 4 0 35 +SetMarkerPath 4 1 251 +SetMarkerPath 5 0 69 +SetMarkerPath 5 1 217 +SetMarkerPath 5 2 37 +SetZone 6 4 +SetMarkerPath 6 0 80 +SetMarkerPath 6 1 153 +SetZone 7 8 +SetMarkerPath 7 0 42 +SetZone 8 3 +SetMarkerPath 8 0 35 +SetMarkerPath 9 0 37 +SetMarkerPath 10 0 42 +SetMarkerPath 12 0 37 +SetMarkerPath 13 0 202 +SetMarkerPath 13 1 204 +SetZone 17 3 +SetMarkerPath 17 0 35 +SetMarkerPath 18 0 35 +SetMarkerPath 19 0 37 +SetMarkerPath 20 0 37 +SetGoal 21 16 +SetZone 21 4 +SetMarkerPath 21 0 83 +SetMarkerPath 21 1 73 +SetMarkerPath 21 2 74 +SetGoal 22 19 +SetZone 22 2 +SetMarkerPath 22 0 194 +SetMarkerPathFlags 22 0 wj +SetMarkerPath 22 1 197 +SetMarkerPath 22 2 254 +SetMarkerPath 22 3 196 +SetMarkerPathFlags 22 3 wj +SetGoal 23 21 +SetZone 23 2 +SetMarkerPath 23 0 187 +SetMarkerPath 23 1 195 +SetGoal 24 16 +SetZone 24 3 +SetMarkerPath 24 0 43 +SetMarkerPath 24 1 162 +SetMarkerPath 24 2 161 +SetGoal 25 16 +SetZone 25 6 +SetMarkerPath 25 0 106 +SetMarkerPath 25 1 107 +SetGoal 26 23 +SetZone 26 10 +SetMarkerPath 26 0 127 +SetMarkerPath 26 1 128 +SetMarkerPath 26 2 136 +SetMarkerPath 26 3 132 +SetGoal 27 24 +SetZone 27 9 +SetMarkerPath 27 0 125 +SetMarkerPath 27 1 126 +SetGoal 28 24 +SetZone 28 1 +SetMarkerPath 28 0 240 +SetMarkerPath 28 1 234 +SetGoal 29 24 +SetZone 29 7 +SetMarkerPath 29 0 180 +SetGoal 30 23 +SetZone 30 7 +SetMarkerPath 30 0 180 +SetGoal 31 16 +SetZone 31 10 +SetMarkerPath 31 0 131 +SetMarkerPath 31 1 40 +SetMarkerPath 31 2 242 +SetGoal 32 1 +SetZone 32 2 +SetMarkerPath 32 1 196 +SetGoal 33 17 +SetZone 33 6 +SetMarkerPath 33 0 109 +SetMarkerPath 33 1 110 +SetMarkerPath 33 2 116 +SetGoal 34 15 +SetZone 34 2 +SetMarkerPath 34 0 198 +SetMarkerPath 34 1 196 +SetMarkerPath 34 2 194 +SetZone 35 6 +SetMarkerPath 35 0 111 +SetMarkerPath 35 1 112 +SetGoal 36 15 +SetZone 36 1 +SetMarkerPath 36 0 236 +SetZone 37 9 +SetMarkerPath 37 0 217 +SetMarkerPath 37 1 5 +SetGoal 38 2 +SetZone 38 1 +SetMarkerPath 38 0 231 +SetMarkerPath 38 1 235 +SetGoal 39 16 +SetZone 39 1 +SetMarkerPath 39 0 62 +SetMarkerPath 39 1 238 +SetMarkerPath 39 2 69 +SetGoal 40 16 +SetZone 40 10 +SetMarkerPath 40 0 131 +SetMarkerPath 40 1 31 +SetMarkerPath 40 2 242 +SetGoal 41 3 +SetZone 41 10 +SetMarkerPath 41 0 134 +SetMarkerPath 41 1 138 +SetMarkerPath 41 2 135 +SetZone 42 10 +SetMarkerPath 42 0 241 +SetGoal 43 16 +SetZone 43 3 +SetMarkerPath 43 0 161 +SetMarkerPath 43 1 24 +SetMarkerPath 43 2 162 +SetGoal 44 21 +SetZone 44 9 +SetMarkerPath 44 0 124 +SetMarkerPath 44 1 211 +SetMarkerPath 44 2 212 +SetMarkerPath 44 3 125 +SetGoal 45 18 +SetZone 45 10 +SetMarkerPath 45 0 135 +SetMarkerPath 45 1 137 +SetGoal 46 18 +SetZone 46 5 +SetMarkerPath 46 0 99 +SetMarkerPath 46 1 100 +SetGoal 47 18 +SetZone 47 2 +SetMarkerPath 47 0 197 +SetMarkerPath 47 1 196 +SetMarkerPathFlags 47 1 wj +SetMarkerPath 47 2 255 +SetMarkerPath 47 3 198 +SetMarkerPathFlags 47 3 wj +SetGoal 48 16 +SetZone 48 11 +SetMarkerPath 48 0 203 +SetMarkerPath 48 1 49 +SetGoal 49 16 +SetZone 49 11 +SetMarkerPath 49 0 203 +SetMarkerPath 49 1 48 +SetZone 50 1 +SetMarkerPath 50 0 228 +SetGoal 51 4 +SetZone 51 4 +SetMarkerPath 51 0 77 +SetZone 52 10 +SetMarkerPath 52 0 137 +SetZone 53 8 +SetMarkerPath 53 0 221 +SetMarkerPath 53 1 220 +SetMarkerPath 53 2 219 +SetGoal 54 24 +SetZone 54 4 +SetMarkerPath 54 0 153 +SetMarkerPath 54 1 152 +SetGoal 55 15 +SetZone 55 8 +SetMarkerPath 55 0 138 +SetMarkerPath 55 1 221 +SetGoal 56 20 +SetZone 56 8 +SetMarkerPath 56 0 140 +SetMarkerPath 56 1 142 +SetGoal 57 18 +SetZone 57 1 +SetMarkerPath 57 0 233 +SetMarkerPath 57 1 232 +SetMarkerPath 57 2 239 +SetMarkerPath 57 3 237 +SetZone 58 9 +SetMarkerPath 58 0 217 +SetMarkerPath 58 1 216 +SetZone 59 11 +SetMarkerPath 59 0 201 +SetMarkerPath 59 1 200 +SetMarkerPath 59 2 202 +SetZone 60 5 +SetMarkerPath 60 0 95 +SetMarkerPath 60 1 96 +SetGoal 61 5 +SetZone 61 9 +SetMarkerPath 61 0 210 +SetMarkerPath 61 1 64 +SetMarkerPathFlags 61 1 j +SetGoal 62 16 +SetZone 62 1 +SetMarkerPath 62 0 238 +SetMarkerPath 62 1 39 +SetMarkerPath 62 2 69 +SetGoal 63 23 +SetZone 63 8 +SetMarkerPath 63 0 143 +SetMarkerPath 63 1 225 +SetMarkerPath 63 2 224 +SetGoal 64 6 +SetZone 64 7 +SetMarkerPath 64 0 170 +SetMarkerPath 64 1 176 +SetMarkerPath 64 2 169 +SetMarkerPath 64 3 172 +SetMarkerPath 64 4 173 +SetMarkerPath 64 5 174 +SetMarkerPath 64 6 175 +SetZone 65 4 +SetMarkerPath 65 0 149 +SetMarkerPath 65 1 70 +SetMarkerPath 65 2 150 +SetMarkerPath 65 3 155 +SetZone 66 2 +SetMarkerPath 66 0 190 +SetMarkerPath 66 1 189 +SetMarkerPath 66 2 164 +SetGoal 67 23 +SetZone 67 4 +SetMarkerPath 67 0 151 +SetMarkerPath 67 1 150 +SetGoal 68 7 +SetZone 68 2 +SetMarkerPath 68 0 193 +SetMarkerPath 68 1 199 +SetZone 69 1 +SetMarkerPath 69 0 238 +SetMarkerPath 69 1 62 +SetMarkerPath 69 2 39 +SetMarkerPath 69 3 240 +SetZone 70 4 +SetMarkerPath 70 0 154 +SetMarkerPath 70 1 150 +SetMarkerPath 70 2 155 +SetMarkerPath 70 3 149 +SetZone 71 4 +SetMarkerPath 71 0 154 +SetMarkerPath 71 1 72 +SetZone 72 4 +SetMarkerPath 72 0 71 +SetMarkerPath 72 1 73 +SetZone 73 4 +SetMarkerPath 73 0 84 +SetMarkerPath 73 1 72 +SetMarkerPath 73 2 74 +SetZone 74 4 +SetMarkerPath 74 0 73 +SetMarkerPath 74 1 75 +SetZone 75 4 +SetMarkerPath 75 0 76 +SetMarkerPath 75 1 82 +SetMarkerPath 75 2 74 +SetZone 76 4 +SetMarkerPath 76 0 78 +SetMarkerPath 76 1 77 +SetMarkerPath 76 2 75 +SetZone 77 4 +SetMarkerPath 77 0 76 +SetMarkerPath 77 1 51 +SetMarkerPath 77 2 71 +SetMarkerPath 77 3 154 +SetMarkerPath 77 4 150 +SetMarkerPath 77 5 151 +SetMarkerPath 77 6 152 +SetMarkerPath 77 7 256 +SetZone 78 4 +SetMarkerPath 78 0 79 +SetMarkerPath 78 1 76 +SetZone 79 4 +SetMarkerPath 79 0 81 +SetMarkerPath 79 1 78 +SetZone 80 4 +SetMarkerPath 80 0 81 +SetZone 81 4 +SetMarkerPath 81 0 80 +SetMarkerPath 81 1 79 +SetZone 82 4 +SetMarkerPath 82 0 75 +SetMarkerPath 82 1 83 +SetZone 83 4 +SetMarkerPath 83 0 82 +SetMarkerPath 83 1 21 +SetMarkerPath 83 2 74 +SetMarkerPath 83 3 73 +SetZone 84 4 +SetMarkerPath 84 0 73 +SetMarkerPath 84 1 85 +SetZone 85 4 +SetMarkerPath 85 0 84 +SetMarkerPath 85 1 86 +SetZone 86 4 +SetMarkerPath 86 0 85 +SetMarkerPath 86 1 87 +SetMarkerPath 86 2 88 +SetMarkerPath 86 3 89 +SetZone 87 4 +SetMarkerPath 87 0 86 +SetMarkerPath 87 1 88 +SetMarkerPath 87 2 72 +SetMarkerPath 87 3 71 +SetMarkerPath 87 4 154 +SetZone 88 4 +SetMarkerPath 88 0 86 +SetMarkerPath 88 1 87 +SetMarkerPath 88 2 89 +SetMarkerPath 88 3 72 +SetMarkerPath 88 4 71 +SetMarkerPath 88 5 154 +SetZone 89 4 +SetMarkerPath 89 0 86 +SetMarkerPath 89 1 88 +SetMarkerPath 89 2 90 +SetZone 90 4 +SetMarkerPath 90 0 89 +SetMarkerPath 90 1 91 +SetZone 91 5 +SetMarkerPath 91 0 90 +SetMarkerPath 91 1 92 +SetZone 92 5 +SetMarkerPath 92 0 91 +SetMarkerPath 92 1 93 +SetMarkerPath 92 2 117 +SetMarkerPath 92 3 118 +SetZone 93 5 +SetMarkerPath 93 0 92 +SetMarkerPath 93 1 94 +SetMarkerPath 93 2 117 +SetZone 94 5 +SetMarkerPath 94 0 93 +SetMarkerPath 94 1 95 +SetZone 95 5 +SetMarkerPath 95 0 94 +SetMarkerPath 95 1 96 +SetZone 96 5 +SetMarkerPath 96 0 95 +SetMarkerPath 96 1 104 +SetZone 97 5 +SetMarkerPath 97 0 101 +SetMarkerPath 97 1 104 +SetMarkerPath 97 2 98 +SetMarkerPath 97 3 105 +SetZone 98 5 +SetMarkerPath 98 0 103 +SetMarkerPath 98 1 99 +SetMarkerPath 98 2 104 +SetMarkerPath 98 3 101 +SetMarkerPath 98 4 97 +SetZone 99 5 +SetMarkerPath 99 0 101 +SetMarkerPath 99 1 98 +SetMarkerPath 99 2 103 +SetMarkerPath 99 3 46 +SetMarkerPathFlags 99 3 j +SetZone 100 5 +SetMarkerPath 100 0 103 +SetMarkerPath 100 1 46 +SetMarkerPathFlags 100 1 j +SetZone 101 5 +SetMarkerPath 101 0 99 +SetMarkerPath 101 1 97 +SetMarkerPath 101 2 104 +SetMarkerPath 101 3 98 +SetMarkerPath 101 4 103 +SetZone 102 5 +SetMarkerPath 102 0 103 +SetMarkerPath 102 1 64 +SetMarkerPathFlags 102 1 j +SetZone 103 5 +SetMarkerPath 103 0 102 +SetMarkerPath 103 1 100 +SetMarkerPath 103 2 98 +SetMarkerPath 103 3 99 +SetMarkerPath 103 4 101 +SetZone 104 5 +SetMarkerPath 104 0 97 +SetMarkerPath 104 1 98 +SetMarkerPath 104 2 101 +SetMarkerPath 104 3 96 +SetZone 105 6 +SetMarkerPath 105 0 97 +SetMarkerPath 105 1 106 +SetZone 106 6 +SetMarkerPath 106 0 105 +SetMarkerPath 106 1 25 +SetMarkerPath 106 2 107 +SetMarkerPath 106 3 108 +SetZone 107 6 +SetMarkerPath 107 0 25 +SetMarkerPath 107 1 106 +SetMarkerPath 107 2 111 +SetMarkerPath 107 3 112 +SetZone 108 6 +SetMarkerPath 108 0 106 +SetMarkerPath 108 1 109 +SetZone 109 6 +SetMarkerPath 109 0 108 +SetMarkerPath 109 1 33 +SetMarkerPath 109 2 110 +SetZone 110 6 +SetMarkerPath 110 0 109 +SetMarkerPath 110 1 33 +SetMarkerPath 110 2 111 +SetZone 111 6 +SetMarkerPath 111 0 110 +SetMarkerPath 111 1 107 +SetMarkerPath 111 2 112 +SetZone 112 6 +SetMarkerPath 112 0 111 +SetMarkerPath 112 1 107 +SetMarkerPath 112 2 115 +SetZone 113 6 +SetMarkerPath 113 0 115 +SetZone 114 6 +SetMarkerPath 114 0 115 +SetMarkerPath 114 1 198 +SetZone 115 6 +SetMarkerPath 115 0 112 +SetMarkerPath 115 1 113 +SetMarkerPath 115 2 114 +SetZone 116 6 +SetMarkerPath 116 0 33 +SetMarkerPath 116 1 51 +SetMarkerPathFlags 116 1 j +SetZone 117 5 +SetMarkerPath 117 0 93 +SetMarkerPath 117 1 92 +SetMarkerPath 117 2 118 +SetMarkerPath 117 3 64 +SetMarkerPathFlags 117 3 j +SetZone 118 5 +SetMarkerPath 118 0 117 +SetMarkerPath 118 1 92 +SetMarkerPath 118 2 119 +SetZone 119 5 +SetMarkerPath 119 0 118 +SetMarkerPath 119 1 120 +SetZone 120 5 +SetMarkerPath 120 0 119 +SetMarkerPath 120 1 121 +SetZone 121 5 +SetMarkerPath 121 0 120 +SetMarkerPath 121 1 227 +SetZone 122 5 +SetMarkerPath 122 0 227 +SetMarkerPath 122 1 123 +SetMarkerPath 122 2 226 +SetZone 123 5 +SetMarkerPath 123 0 122 +SetMarkerPath 123 1 124 +SetZone 124 9 +SetMarkerPath 124 0 123 +SetMarkerPath 124 1 44 +SetMarkerPath 124 2 125 +SetMarkerPath 124 3 212 +SetZone 125 9 +SetMarkerPath 125 0 124 +SetMarkerPath 125 1 27 +SetMarkerPath 125 2 44 +SetMarkerPath 125 3 212 +SetZone 126 9 +SetMarkerPath 126 0 27 +SetMarkerPath 126 1 127 +SetZone 127 10 +SetMarkerPath 127 0 126 +SetMarkerPath 127 1 26 +SetZone 128 10 +SetMarkerPath 128 0 26 +SetMarkerPath 128 1 129 +SetMarkerPath 128 2 136 +SetMarkerPath 128 3 132 +SetZone 129 10 +SetMarkerPath 129 0 128 +SetMarkerPath 129 1 130 +SetZone 130 10 +SetMarkerPath 130 0 129 +SetMarkerPath 130 1 131 +SetZone 131 10 +SetMarkerPath 131 0 130 +SetMarkerPath 131 1 31 +SetMarkerPath 131 2 40 +SetMarkerPath 131 3 242 +SetZone 132 10 +SetMarkerPath 132 0 136 +SetMarkerPath 132 1 128 +SetMarkerPath 132 2 26 +SetMarkerPath 132 3 133 +SetMarkerPath 132 4 134 +SetZone 133 10 +SetMarkerPath 133 0 132 +SetMarkerPath 133 1 134 +SetMarkerPath 133 2 137 +SetZone 134 10 +SetMarkerPath 134 0 133 +SetMarkerPath 134 1 41 +SetMarkerPath 134 2 135 +SetMarkerPath 134 3 137 +SetMarkerPath 134 4 132 +SetZone 135 10 +SetMarkerPath 135 0 134 +SetMarkerPath 135 1 45 +SetMarkerPath 135 2 137 +SetMarkerPath 135 3 41 +SetZone 136 10 +SetMarkerPath 136 0 26 +SetMarkerPath 136 1 128 +SetMarkerPath 136 2 132 +SetZone 137 10 +SetMarkerPath 137 0 45 +SetMarkerPath 137 1 52 +SetMarkerPath 137 2 135 +SetMarkerPath 137 3 134 +SetMarkerPath 137 4 133 +SetZone 138 8 +SetMarkerPath 138 0 7 +SetMarkerPath 138 1 55 +SetMarkerPath 138 2 141 +SetMarkerPath 138 3 139 +SetZone 139 8 +SetMarkerPath 139 0 138 +SetMarkerPath 139 1 140 +SetMarkerPath 139 2 141 +SetZone 140 8 +SetMarkerPath 140 0 139 +SetMarkerPath 140 1 56 +SetMarkerPath 140 2 224 +SetZone 141 8 +SetMarkerPath 141 0 138 +SetMarkerPath 141 1 223 +SetMarkerPath 141 2 139 +SetZone 142 8 +SetMarkerPath 142 0 56 +SetMarkerPath 142 1 143 +SetZone 143 8 +SetMarkerPath 143 0 142 +SetMarkerPath 143 1 144 +SetMarkerPath 143 2 63 +SetZone 144 8 +SetMarkerPath 144 0 143 +SetMarkerPath 144 1 145 +SetZone 145 8 +SetMarkerPath 145 0 144 +SetMarkerPath 145 1 146 +SetZone 146 8 +SetMarkerPath 146 0 145 +SetMarkerPath 146 1 147 +SetZone 147 8 +SetMarkerPath 147 0 146 +SetMarkerPath 147 1 148 +SetZone 148 4 +SetMarkerPath 148 0 147 +SetMarkerPath 148 1 149 +SetZone 149 4 +SetMarkerPath 149 0 155 +SetMarkerPath 149 1 148 +SetMarkerPath 149 2 70 +SetMarkerPath 149 3 154 +SetZone 150 4 +SetMarkerPath 150 0 151 +SetMarkerPath 150 1 67 +SetMarkerPath 150 2 70 +SetMarkerPath 150 3 154 +SetMarkerPath 150 4 155 +SetZone 151 4 +SetMarkerPath 151 0 152 +SetMarkerPath 151 1 150 +SetMarkerPath 151 2 67 +SetMarkerPath 151 3 246 +SetZone 152 4 +SetMarkerPath 152 0 153 +SetMarkerPath 152 1 151 +SetZone 153 4 +SetMarkerPath 153 1 152 +SetZone 154 4 +SetMarkerPath 154 0 70 +SetMarkerPath 154 1 71 +SetMarkerPath 154 2 150 +SetMarkerPath 154 3 155 +SetMarkerPath 154 4 149 +SetZone 155 4 +SetMarkerPath 155 0 70 +SetMarkerPath 155 1 150 +SetMarkerPath 155 2 149 +SetMarkerPath 155 3 154 +SetMarkerPath 155 4 156 +SetZone 156 4 +SetMarkerPath 156 0 155 +SetMarkerPath 156 1 157 +SetMarkerPath 156 2 158 +SetZone 157 3 +SetMarkerPath 157 0 156 +SetMarkerPath 157 1 158 +SetMarkerPath 157 2 166 +SetZone 158 3 +SetMarkerPath 158 0 156 +SetMarkerPath 158 1 157 +SetMarkerPath 158 2 159 +SetZone 159 3 +SetMarkerPath 159 0 160 +SetMarkerPath 159 1 158 +SetZone 160 3 +SetMarkerPath 160 0 161 +SetMarkerPath 160 1 159 +SetMarkerPath 160 2 253 +SetZone 161 3 +SetMarkerPath 161 0 162 +SetMarkerPath 161 1 43 +SetMarkerPath 161 2 24 +SetMarkerPath 161 3 160 +SetMarkerPath 161 4 253 +SetZone 162 3 +SetMarkerPath 162 0 163 +SetMarkerPath 162 1 161 +SetMarkerPath 162 2 24 +SetMarkerPath 162 3 43 +SetZone 163 2 +SetMarkerPath 163 0 188 +SetMarkerPath 163 1 162 +SetZone 164 2 +SetMarkerPath 164 0 165 +SetMarkerPath 164 1 188 +SetMarkerPath 164 2 189 +SetMarkerPath 164 3 198 +SetZone 165 2 +SetMarkerPath 165 0 182 +SetMarkerPath 165 1 164 +SetMarkerPath 165 2 194 +SetZone 166 3 +SetMarkerPath 166 0 157 +SetMarkerPath 166 1 167 +SetZone 167 3 +SetMarkerPath 167 0 166 +SetMarkerPath 167 1 168 +SetZone 168 7 +SetMarkerPath 168 0 167 +SetMarkerPath 168 1 169 +SetZone 169 7 +SetMarkerPath 169 0 168 +SetMarkerPath 169 1 170 +SetMarkerPath 169 2 176 +SetZone 170 7 +SetMarkerPath 170 0 169 +SetMarkerPath 170 1 171 +SetMarkerPath 170 2 172 +SetMarkerPath 170 3 176 +SetZone 171 7 +SetMarkerPath 171 0 170 +SetMarkerPath 171 1 172 +SetMarkerPath 171 2 218 +SetZone 172 7 +SetMarkerPath 172 0 171 +SetMarkerPath 172 1 170 +SetMarkerPath 172 2 173 +SetZone 173 7 +SetMarkerPath 173 0 172 +SetMarkerPath 173 1 174 +SetMarkerPath 173 2 200 +SetMarkerPath 173 3 64 +SetMarkerPathFlags 173 3 rj +SetRocketJumpPathFields 173 3 56.0 148.0 5 +SetZone 174 7 +SetMarkerPath 174 0 173 +SetMarkerPath 174 1 175 +SetMarkerPath 174 2 176 +SetZone 175 7 +SetMarkerPath 175 0 174 +SetMarkerPath 175 1 176 +SetMarkerPath 175 2 177 +SetMarkerPath 175 3 250 +SetZone 176 7 +SetMarkerPath 176 0 174 +SetMarkerPath 176 1 175 +SetMarkerPath 176 2 250 +SetMarkerPath 176 3 169 +SetMarkerPath 176 4 170 +SetZone 177 7 +SetMarkerPath 177 0 175 +SetMarkerPath 177 1 178 +SetZone 178 7 +SetMarkerPath 178 0 177 +SetMarkerPath 178 1 179 +SetMarkerPath 178 2 180 +SetZone 179 7 +SetMarkerPath 179 0 178 +SetMarkerPath 179 1 180 +SetMarkerPath 179 2 181 +SetZone 180 7 +SetMarkerPath 180 0 179 +SetMarkerPath 180 1 178 +SetMarkerPath 180 2 30 +SetMarkerPathFlags 180 2 j +SetMarkerPath 180 3 29 +SetMarkerPathFlags 180 3 j +SetZone 181 2 +SetMarkerPath 181 0 179 +SetMarkerPath 181 1 182 +SetMarkerPath 181 2 183 +SetMarkerPath 181 3 194 +SetZone 182 2 +SetMarkerPath 182 0 181 +SetMarkerPath 182 1 165 +SetMarkerPath 182 2 194 +SetZone 183 2 +SetMarkerPath 183 0 184 +SetMarkerPath 183 1 181 +SetMarkerPath 183 2 194 +SetZone 184 2 +SetMarkerPath 184 0 185 +SetMarkerPath 184 1 183 +SetZone 185 2 +SetMarkerPath 185 0 187 +SetMarkerPath 185 1 186 +SetMarkerPath 185 2 184 +SetZone 186 2 +SetMarkerPath 186 0 187 +SetMarkerPath 186 1 185 +SetMarkerPath 186 2 228 +SetZone 187 2 +SetMarkerPath 187 0 23 +SetMarkerPath 187 1 186 +SetMarkerPath 187 2 185 +SetZone 188 2 +SetMarkerPath 188 0 164 +SetMarkerPath 188 1 163 +SetMarkerPath 188 2 189 +SetMarkerPath 188 3 198 +SetZone 189 2 +SetMarkerPath 189 0 190 +SetMarkerPath 189 1 164 +SetMarkerPath 189 2 188 +SetMarkerPath 189 4 198 +SetZone 190 2 +SetMarkerPath 190 0 191 +SetMarkerPath 190 1 189 +SetZone 191 2 +SetMarkerPath 191 0 192 +SetMarkerPath 191 1 190 +SetZone 192 2 +SetMarkerPath 192 0 193 +SetMarkerPath 192 1 191 +SetZone 193 2 +SetMarkerPath 193 0 68 +SetMarkerPath 193 1 192 +SetZone 194 2 +SetMarkerPath 194 0 34 +SetMarkerPath 194 1 182 +SetMarkerPath 194 2 165 +SetMarkerPath 194 3 181 +SetMarkerPath 194 4 183 +SetZone 195 2 +SetMarkerPath 195 0 23 +SetMarkerPath 195 1 196 +SetMarkerPathFlags 195 1 j +SetZone 196 2 +SetMarkerPath 196 0 32 +SetMarkerPath 196 1 34 +SetMarkerPath 196 2 197 +SetMarkerPath 196 3 47 +SetMarkerPath 196 4 254 +SetMarkerPath 196 5 22 +SetZone 197 2 +SetMarkerPath 197 0 47 +SetMarkerPath 197 1 34 +SetMarkerPath 197 3 196 +SetMarkerPathFlags 197 3 wj +SetZone 198 2 +SetMarkerPath 198 0 189 +SetMarkerPath 198 1 164 +SetMarkerPath 198 2 188 +SetMarkerPath 198 3 34 +SetMarkerPath 198 4 255 +SetZone 199 2 +SetMarkerPath 199 0 68 +SetMarkerPath 199 1 196 +SetMarkerPathFlags 199 1 j +SetZone 200 11 +SetMarkerPath 200 0 173 +SetMarkerPath 200 1 203 +SetMarkerPath 200 2 201 +SetZone 201 11 +SetMarkerPath 201 0 203 +SetMarkerPath 201 1 200 +SetMarkerPath 201 2 202 +SetZone 202 11 +SetMarkerPath 202 0 201 +SetMarkerPath 202 1 13 +SetZone 203 11 +SetMarkerPath 203 0 200 +SetMarkerPath 203 1 48 +SetMarkerPath 203 2 49 +SetMarkerPath 203 3 201 +SetZone 204 9 +SetMarkerPath 204 0 201 +SetMarkerPath 204 1 205 +SetMarkerPath 204 2 214 +SetMarkerPath 204 3 215 +SetZone 205 9 +SetMarkerPath 205 0 206 +SetMarkerPath 205 1 204 +SetZone 206 9 +SetMarkerPath 206 0 208 +SetMarkerPath 206 1 205 +SetZone 207 9 +SetMarkerPath 207 0 209 +SetMarkerPath 207 1 208 +SetZone 208 9 +SetMarkerPath 208 0 207 +SetMarkerPath 208 1 206 +SetZone 209 9 +SetMarkerPath 209 0 210 +SetMarkerPathFlags 209 0 j +SetMarkerPath 209 1 207 +SetZone 210 9 +SetMarkerPath 210 0 209 +SetMarkerPath 210 1 61 +SetMarkerPath 210 2 211 +SetZone 211 9 +SetMarkerPath 211 0 44 +SetZone 212 9 +SetMarkerPath 212 0 213 +SetMarkerPath 212 1 44 +SetMarkerPath 212 2 124 +SetMarkerPath 212 3 125 +SetZone 213 9 +SetMarkerPath 213 0 214 +SetMarkerPath 213 1 212 +SetZone 214 9 +SetMarkerPath 214 0 204 +SetMarkerPath 214 1 213 +SetZone 215 9 +SetMarkerPath 215 0 204 +SetMarkerPath 215 1 216 +SetZone 216 9 +SetMarkerPath 216 0 215 +SetMarkerPath 216 1 217 +SetZone 217 9 +SetMarkerPath 217 0 216 +SetMarkerPath 217 1 5 +SetZone 218 7 +SetMarkerPath 218 0 219 +SetMarkerPath 218 1 171 +SetZone 219 8 +SetMarkerPath 219 0 220 +SetMarkerPath 219 1 218 +SetMarkerPath 219 2 223 +SetZone 220 8 +SetMarkerPath 220 0 221 +SetMarkerPath 220 1 219 +SetZone 221 8 +SetMarkerPath 221 0 55 +SetMarkerPath 221 1 220 +SetZone 222 8 +SetMarkerPath 222 0 223 +SetMarkerPath 222 1 225 +SetZone 223 8 +SetMarkerPath 223 0 141 +SetMarkerPath 223 1 225 +SetZone 224 8 +SetMarkerPath 224 0 225 +SetMarkerPath 224 1 140 +SetZone 225 8 +SetMarkerPath 225 0 224 +SetMarkerPath 225 1 223 +SetZone 226 5 +SetMarkerPath 226 0 122 +SetMarkerPath 226 1 227 +SetMarkerPath 226 2 64 +SetMarkerPathFlags 226 2 j +SetZone 227 5 +SetMarkerPath 227 0 121 +SetMarkerPath 227 1 122 +SetMarkerPath 227 2 226 +SetZone 228 1 +SetMarkerPath 228 0 229 +SetMarkerPath 228 1 186 +SetZone 229 1 +SetMarkerPath 229 0 230 +SetMarkerPath 229 1 234 +SetMarkerPath 229 2 228 +SetZone 230 1 +SetMarkerPath 230 0 229 +SetMarkerPath 230 1 57 +SetMarkerPathFlags 230 1 j +SetZone 231 1 +SetMarkerPath 231 0 38 +SetMarkerPath 231 1 232 +SetZone 232 1 +SetMarkerPath 232 0 233 +SetMarkerPath 232 1 231 +SetMarkerPath 232 2 235 +SetZone 233 1 +SetMarkerPath 233 0 234 +SetMarkerPath 233 1 232 +SetZone 234 1 +SetMarkerPath 234 0 229 +SetMarkerPath 234 1 233 +SetMarkerPath 234 2 28 +SetMarkerPath 234 3 240 +SetZone 235 1 +SetMarkerPath 235 0 38 +SetMarkerPath 235 1 232 +SetMarkerPath 235 2 236 +SetMarkerPath 235 3 239 +SetZone 236 1 +SetMarkerPath 236 0 235 +SetMarkerPath 236 1 239 +SetMarkerPath 236 2 36 +SetMarkerPathFlags 236 2 j +SetZone 237 1 +SetMarkerPath 237 0 239 +SetMarkerPath 237 1 238 +SetMarkerPathFlags 237 1 j +SetZone 238 1 +SetMarkerPath 238 0 237 +SetMarkerPath 238 1 62 +SetMarkerPath 238 2 39 +SetMarkerPath 238 3 69 +SetZone 239 1 +SetMarkerPath 239 0 235 +SetMarkerPath 239 1 237 +SetMarkerPath 239 2 236 +SetZone 240 1 +SetMarkerPath 240 0 69 +SetMarkerPath 240 1 28 +SetMarkerPath 240 2 234 +SetZone 241 10 +SetMarkerPath 241 0 42 +SetMarkerPath 241 1 133 +SetMarkerPath 241 2 132 +SetZone 242 10 +SetMarkerPath 242 0 31 +SetMarkerPath 242 1 40 +SetMarkerPath 242 2 131 +SetZone 243 4 +SetMarkerPath 243 0 244 +SetMarkerPath 243 1 246 +SetZone 244 4 +SetMarkerPath 244 0 245 +SetZone 245 4 +SetMarkerPath 245 0 151 +SetMarkerPath 245 1 150 +SetZone 246 4 +SetMarkerPath 246 0 153 +SetMarkerPath 246 1 152 +SetMarkerPath 246 2 151 +SetZone 247 7 +SetMarkerPath 247 0 248 +SetMarkerPathFlags 247 0 j +SetMarkerPath 247 1 172 +SetMarkerPath 247 2 171 +SetZone 248 7 +SetMarkerPath 248 0 172 +SetMarkerPathAngleHint 248 0 90 +SetMarkerPath 248 1 173 +SetMarkerPath 248 2 171 +SetZone 249 7 +SetMarkerPath 249 0 170 +SetMarkerPath 249 1 171 +SetZone 250 7 +SetMarkerPath 250 0 176 +SetMarkerPath 250 1 175 +SetZone 251 3 +SetMarkerPath 251 0 252 +SetMarkerPath 251 1 4 +SetZone 252 3 +SetMarkerPath 252 0 253 +SetMarkerPath 252 1 251 +SetZone 253 3 +SetMarkerPath 253 0 161 +SetMarkerPath 253 1 160 +SetMarkerPath 253 2 252 +SetZone 254 2 +SetMarkerPath 254 0 34 +SetMarkerPath 254 1 194 +SetMarkerPath 254 3 196 +SetZone 255 2 +SetMarkerPath 255 0 47 +SetMarkerPath 255 1 34 +SetMarkerPath 255 2 198 +SetZone 256 4 +SetMarkerPath 256 0 77 +SetMarkerPathFlags 256 0 j +SetMarkerPath 256 1 71 +SetMarkerPath 256 2 244 +SetMarkerPath 256 3 72 +SetZone 257 10 +SetMarkerPath 257 0 138 +SetZone 258 10 +SetMarkerPath 258 0 138 From 125f7d16dafe665289306a5fe4df049f6205b17d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Linus=20B=C3=A4ckman?= Date: Tue, 16 Sep 2025 20:43:48 +0200 Subject: [PATCH 17/34] Add bot support for map Qube --- .../example-configs/ktx/bots/maps/qube.bot | 1423 +++++++++++++++++ 1 file changed, 1423 insertions(+) create mode 100644 resources/example-configs/ktx/bots/maps/qube.bot diff --git a/resources/example-configs/ktx/bots/maps/qube.bot b/resources/example-configs/ktx/bots/maps/qube.bot new file mode 100644 index 00000000..099fe4b2 --- /dev/null +++ b/resources/example-configs/ktx/bots/maps/qube.bot @@ -0,0 +1,1423 @@ +CreateMarker 117 437 -24 +CreateMarker 234 554 -24 +CreateMarker 333 629 -24 +CreateMarker 490 504 -24 +CreateMarker 607 372 -24 +CreateMarker 702 279 -8 +CreateMarker 702 113 16 +CreateMarker 703 -65 56 +CreateMarker 288 743 -24 +CreateMarker 144 742 -88 +CreateMarker -4 742 -168 +CreateMarker -20 610 -168 +CreateMarker 150 555 -168 +CreateMarker 273 429 -168 +CreateMarker 352 351 -168 +CreateMarker -220 454 -168 +CreateMarker -285 358 -168 +CreateMarker -283 182 -200 +CreateMarker -300 -103 -200 +CreateMarker -316 -344 -200 +CreateMarker -314 -579 -232 +CreateMarker -313 -727 -232 +CreateMarker -319 -904 -232 +CreateMarker -528 -918 -312 +CreateMarker -716 -916 -376 +CreateMarker -389 -724 -376 +CreateMarker -443 -612 -376 +CreateMarker -694 -640 -376 +CreateMarker -576 -592 -376 +CreateMarker -304 15 -200 +CreateMarker -125 538 -168 +CreateMarker -389 442 -168 +CreateMarker -544 445 -168 +CreateMarker -719 442 -120 +CreateMarker -717 311 -56 +CreateMarker -699 169 -24 +CreateMarker -493 165 24 +CreateMarker -468 287 24 +CreateMarker -409 425 28 +CreateMarker -274 435 95 +CreateMarker -144 423 152 +CreateMarker -26 340 152 +CreateMarker -7 469 152 +CreateMarker -119 170 152 +CreateMarker 12 93 152 +CreateMarker -122 80 152 +CreateMarker 26 240 152 +CreateMarker -447 26 24 +CreateMarker -455 -120 24 +CreateMarker -557 -202 24 +CreateMarker -335 -223 24 +CreateMarker -683 -212 -8 +CreateMarker -795 -233 -24 +CreateMarker -849 -366 -24 +CreateMarker -945 -488 -24 +CreateMarker -1083 -583 -24 +CreateMarker -981 -615 -11 +CreateMarker -852 -615 54 +CreateMarker -739 -584 80 +CreateMarker -737 -495 120 +CreateMarker -735 -347 152 +CreateMarker -602 -360 152 +CreateMarker -471 -413 152 +CreateMarker -332 -301 152 +CreateMarker -1202 -577 -24 +CreateMarker -1353 -573 -24 +CreateMarker -1340 -448 -24 +CreateMarker -1112 -444 -112 +CreateMarker -1205 -445 -69 +CreateMarker -1125 -305 -112 +CreateMarker -1050 -224 -112 +CreateMarker -921 -121 -112 +CreateMarker -947 -351 -112 +CreateMarker -960 -232 -112 +CreateMarker -1458 -453 -24 +CreateMarker -1380 -198 -24 +CreateMarker -1474 -195 -24 +CreateMarker -1467 -45 -24 +CreateMarker -1461 82 -24 +CreateMarker -1293 79 -24 +CreateMarker -1138 88 -24 +CreateMarker -1475 -313 -24 +CreateMarker -1553 -529 -24 +CreateMarker -1682 -567 -24 +CreateMarker -1623 -781 -24 +CreateMarker -1673 -687 -24 +CreateMarker -1408 -870 24 +CreateMarker -1613 -925 0 +CreateMarker -1579 -1073 24 +CreateMarker -1393 -1132 24 +CreateMarker -1233 -1165 48 +CreateMarker -1094 -1165 48 +CreateMarker -981 -1288 48 +CreateMarker -970 -1162 52 +CreateMarker -999 -1022 48 +CreateMarker -883 -968 72 +CreateMarker -931 -1370 56 +CreateMarker -749 -1372 72 +CreateMarker -774 -1170 24 +CreateMarker -497 -1171 24 +CreateMarker -488 -1283 24 +CreateMarker -386 -1226 24 +CreateMarker -623 -1173 24 +CreateMarker -613 -985 24 +CreateMarker -460 -974 24 +CreateMarker -408 -1091 24 +CreateMarker -219 -1001 24 +CreateMarker -72 -875 24 +CreateMarker -214 -869 24 +CreateMarker -303 -941 24 +CreateMarker -291 -1084 24 +CreateMarker -191 -1205 -48 +CreateMarker -64 -1208 -104 +CreateMarker -41 -1091 -104 +CreateMarker -41 -931 -104 +CreateMarker -341 -854 -104 +CreateMarker -449 -772 -104 +CreateMarker -531 -671 -104 +CreateMarker -684 -912 -104 +CreateMarker -608 -791 -104 +CreateMarker -446 -897 -104 +CreateMarker -577 -919 -104 +CreateMarker -524 -568 -128 +CreateMarker -523 -434 -176 +CreateMarker -512 -331 -200 +CreateMarker -416 -249 -200 +CreateMarker -312 -237 -200 +CreateMarker -428 8 -168 +CreateMarker -557 -53 -168 +CreateMarker -739 -60 -136 +CreateMarker -850 -72 -112 +CreateMarker -650 -55 -168 +CreateMarker -879 -238 -24 +CreateMarker -111 362 -248 +CreateMarker -105 203 -248 +CreateMarker 156 282 -248 +CreateMarker 311 269 -248 +CreateMarker 430 232 -248 +CreateMarker 466 87 -248 +CreateMarker 360 -27 -248 +CreateMarker 256 8 -248 +CreateMarker 158 88 -248 +CreateMarker 180 190 -248 +CreateMarker 235 -209 -232 +CreateMarker 281 -113 -232 +CreateMarker 134 -113 -232 +CreateMarker -65 -107 -200 +CreateMarker -193 -176 -200 +CreateMarker -197 -4 -200 +CreateMarker -5 37 -248 +CreateMarker 245 -312 -248 +CreateMarker 233 -426 -264 +CreateMarker 351 -486 -264 +CreateMarker 557 -667 -264 +CreateMarker 499 -567 -264 +CreateMarker 684 -567 -264 +CreateMarker 566 -476 -264 +CreateMarker 516 -810 -296 +CreateMarker 453 -883 -328 +CreateMarker 277 -890 -344 +CreateMarker 383 -979 -344 +CreateMarker 383 -1079 -376 +CreateMarker 391 -1184 -360 +CreateMarker 391 -1215 -320 +CreateMarker 288 -1277 -360 +CreateMarker 337 -1275 -320 +CreateMarker 291 -1187 -376 +CreateMarker 232 -1193 -408 +CreateMarker 165 -1194 -478 +CreateMarker 327 -1182 -579 +CreateMarker 43 -950 -545 +CreateMarker 29 -787 -502 +CreateMarker -147 -732 -471 +CreateMarker -328 -727 -453 +CreateMarker -48 -802 -539 +CreateMarker -138 -590 -376 +CreateMarker -116 -613 -446 +CreateMarker -135 -425 -376 +CreateMarker 399 -723 -499 +CreateMarker 208 -704 -498 +CreateMarker -1047 39 -24 +CreateMarker -1190 -34 -24 +CreateMarker 532 653 -24 +CreateMarker 502 -60 56 +CreateMarker -623 -760 -376 +CreateMarker -975 -192 152 +CreateMarker -758 -209 152 +CreateMarker -737 -30 152 +CreateMarker -634 34 152 +CreateMarker -529 32 152 +CreateMarker -867 -285 152 +CreateMarker -886 -186 152 +CreateMarker -843 -65 152 +CreateMarker -989 -240 152 +CreateMarker 192 -1092 -104 +CreateMarker 561 -949 -104 +CreateMarker 480 -1027 -104 +CreateMarker 126 -839 -104 +CreateMarker 259 -859 -104 +CreateMarker 360 -970 -104 +CreateMarker -16 -852 -104 +CreateMarker 101 -976 -104 +CreateMarker 572 -802 -40 +CreateMarker 577 -625 24 +CreateMarker 689 -647 40 +CreateMarker 691 -765 104 +CreateMarker 686 -908 152 +CreateMarker 594 -960 152 +CreateMarker 476 -949 152 +CreateMarker 410 -1092 152 +CreateMarker 575 -1107 152 +CreateMarker 282 -1198 152 +CreateMarker 170 -1274 152 +CreateMarker 39 -1269 152 +CreateMarker -72 -1337 152 +CreateMarker -39 -1470 152 +CreateMarker 140 -1466 152 +CreateMarker 478 -834 181 +CreateMarker 481 -678 216 +CreateMarker 468 -526 216 +CreateMarker 253 -532 152 +CreateMarker 158 -602 152 +CreateMarker 23 -636 152 +CreateMarker -93 -786 152 +CreateMarker 477 -526 24 +CreateMarker 382 -525 24 +CreateMarker -64 -1077 152 +CreateMarker -66 -1239 152 +CreateMarker 209 -300 152 +SetGoal 1 1 +SetZone 1 7 +SetMarkerPath 1 0 283 +SetMarkerPath 1 1 284 +SetGoal 2 2 +SetZone 2 4 +SetMarkerPath 2 0 156 +SetMarkerPath 2 1 164 +SetMarkerPath 2 2 159 +SetMarkerPath 2 3 163 +SetZone 3 5 +SetMarkerPath 3 0 255 +SetMarkerPath 3 1 260 +SetMarkerPath 3 2 257 +SetGoal 4 3 +SetZone 4 1 +SetMarkerPath 4 0 141 +SetMarkerPath 4 1 241 +SetZone 5 13 +SetMarkerPath 5 0 22 +SetMarkerPath 5 1 220 +SetZone 6 5 +SetMarkerPath 6 0 173 +SetMarkerPath 6 1 174 +SetMarkerPath 6 2 255 +SetZone 7 6 +SetMarkerPath 7 0 51 +SetMarkerPath 7 1 264 +SetMarkerPath 7 2 286 +SetMarkerPath 7 3 53 +SetMarkerPath 7 4 285 +SetZone 8 4 +SetMarkerPath 8 0 30 +SetMarkerPath 8 1 161 +SetMarkerPath 8 2 162 +SetGoal 9 16 +SetZone 9 1 +SetMarkerPath 9 0 132 +SetMarkerPath 9 1 23 +SetMarkerPath 9 2 131 +SetMarkerPath 9 3 130 +SetMarkerPath 9 4 134 +SetGoal 10 19 +SetZone 10 9 +SetMarkerPath 10 0 29 +SetMarkerPath 10 1 59 +SetMarkerPath 10 2 245 +SetGoal 11 24 +SetZone 11 8 +SetMarkerPath 11 0 186 +SetMarkerPath 11 1 185 +SetGoal 12 24 +SetZone 12 2 +SetMarkerPath 12 0 253 +SetZone 13 6 +SetMarkerPath 13 0 277 +SetZone 14 4 +SetMarkerPath 14 0 13 +SetMarkerPath 14 1 158 +SetGoal 15 4 +SetZone 15 11 +SetMarkerPath 15 0 208 +SetMarkerPath 15 1 207 +SetMarkerPath 15 2 206 +SetMarkerPath 15 3 204 +SetMarkerPath 15 4 237 +SetZone 16 11 +SetMarkerPath 16 0 91 +SetMarkerPath 16 1 72 +SetMarkerPath 16 2 71 +SetZone 17 3 +SetMarkerPath 17 0 27 +SetGoal 18 23 +SetZone 18 15 +SetMarkerPath 18 0 109 +SetMarkerPath 18 1 111 +SetZone 19 15 +SetMarkerPath 19 0 99 +SetMarkerPath 19 1 98 +SetGoal 20 17 +SetZone 20 16 +SetMarkerPath 20 0 103 +SetMarkerPath 20 1 107 +SetMarkerPath 20 2 102 +SetMarkerPath 20 3 64 +SetMarkerPathFlags 20 3 j +SetZone 21 16 +SetGoal 22 18 +SetZone 22 13 +SetMarkerPath 22 0 220 +SetGoal 23 18 +SetZone 23 1 +SetMarkerPath 23 0 9 +SetMarkerPath 23 1 131 +SetMarkerPath 23 2 130 +SetGoal 24 18 +SetZone 24 6 +SetMarkerPath 24 0 267 +SetMarkerPath 24 1 268 +SetMarkerPath 24 2 269 +SetGoal 25 21 +SetZone 25 2 +SetMarkerPath 25 0 123 +SetGoal 26 21 +SetZone 26 4 +SetMarkerPath 26 0 167 +SetMarkerPath 26 1 168 +SetMarkerPath 26 2 169 +SetMarkerPath 26 3 170 +SetGoal 27 16 +SetZone 27 3 +SetMarkerPath 27 0 146 +SetMarkerPath 27 1 145 +SetGoal 28 22 +SetZone 28 3 +SetMarkerPath 28 0 147 +SetMarkerPath 28 1 149 +SetMarkerPath 28 2 150 +SetGoal 29 19 +SetZone 29 9 +SetMarkerPath 29 0 85 +SetMarkerPath 29 1 10 +SetMarkerPath 29 2 88 +SetMarkerPath 29 3 59 +SetMarkerPath 29 4 245 +SetGoal 30 16 +SetZone 30 4 +SetMarkerPath 30 0 161 +SetGoal 31 16 +SetZone 31 5 +SetMarkerPath 31 0 32 +SetMarkerPath 31 1 176 +SetGoal 32 16 +SetZone 32 5 +SetMarkerPath 32 0 175 +SetMarkerPath 32 1 31 +SetMarkerPath 32 2 261 +SetGoal 33 18 +SetZone 33 5 +SetMarkerPath 33 0 177 +SetMarkerPath 33 1 178 +SetMarkerPath 33 2 183 +SetGoal 34 16 +SetZone 34 9 +SetMarkerPath 34 0 87 +SetMarkerPath 34 1 35 +SetMarkerPath 34 2 86 +SetGoal 35 16 +SetZone 35 9 +SetMarkerPath 35 0 34 +SetMarkerPath 35 1 236 +SetGoal 36 24 +SetZone 36 12 +SetMarkerPath 36 0 217 +SetMarkerPath 36 1 216 +SetGoal 37 23 +SetZone 37 10 +SetMarkerPath 37 0 232 +SetMarkerPath 37 1 233 +SetMarkerPath 37 2 237 +SetGoal 38 23 +SetZone 38 10 +SetMarkerPath 38 0 232 +SetMarkerPath 38 1 233 +SetMarkerPath 39 0 40 +SetMarkerPath 39 1 230 +SetZone 40 12 +SetMarkerPath 40 0 216 +SetMarkerPath 40 1 215 +SetMarkerPath 40 2 213 +SetZone 41 2 +SetMarkerPath 41 0 123 +SetMarkerPath 41 1 124 +SetGoal 42 20 +SetZone 42 11 +SetMarkerPath 42 0 75 +SetMarkerPath 42 1 199 +SetMarkerPath 42 2 200 +SetMarkerPath 42 3 201 +SetMarkerPath 42 4 203 +SetMarkerPath 42 5 198 +SetMarkerPath 42 6 197 +SetMarkerPath 42 7 202 +SetGoal 43 19 +SetZone 43 16 +SetMarkerPath 43 0 101 +SetMarkerPath 43 1 103 +SetMarkerPath 43 2 102 +SetGoal 44 23 +SetZone 44 11 +SetMarkerPath 44 0 57 +SetZone 45 12 +SetMarkerPath 45 0 3 +SetMarkerPath 45 1 216 +SetGoal 46 5 +SetZone 46 14 +SetMarkerPath 46 0 61 +SetGoal 47 6 +SetZone 47 13 +SetMarkerPath 47 0 224 +SetMarkerPath 47 1 226 +SetGoal 48 7 +SetZone 48 10 +SetMarkerPath 48 0 229 +SetMarkerPath 48 1 230 +SetMarkerPath 48 2 231 +SetGoal 49 16 +SetZone 49 16 +SetMarkerPath 49 0 104 +SetMarkerPath 49 1 106 +SetGoal 50 24 +SetZone 50 11 +SetMarkerPath 50 0 91 +SetMarkerPath 50 1 76 +SetMarkerPath 50 2 77 +SetMarkerPath 50 3 92 +SetGoal 51 15 +SetZone 51 6 +SetMarkerPath 51 0 264 +SetMarkerPath 51 1 53 +SetGoal 52 24 +SetZone 52 6 +SetMarkerPath 52 0 287 +SetMarkerPath 52 1 54 +SetGoal 53 16 +SetZone 53 6 +SetMarkerPath 53 0 286 +SetMarkerPath 53 1 285 +SetMarkerPath 53 2 51 +SetGoal 54 23 +SetZone 54 6 +SetMarkerPath 54 0 287 +SetMarkerPath 54 1 52 +SetMarkerPath 54 2 288 +SetGoal 55 23 +SetZone 55 14 +SetMarkerPath 55 0 66 +SetMarkerPath 55 1 65 +SetGoal 56 16 +SetZone 56 14 +SetMarkerPath 56 0 68 +SetMarkerPath 56 1 244 +SetGoal 57 16 +SetZone 57 11 +SetMarkerPath 57 0 58 +SetMarkerPath 57 1 196 +SetGoal 58 16 +SetZone 58 11 +SetMarkerPath 58 0 195 +SetMarkerPath 58 1 57 +SetMarkerPath 58 2 194 +SetGoal 59 8 +SetZone 59 9 +SetMarkerPath 59 0 86 +SetMarkerPath 59 2 29 +SetMarkerPath 59 3 10 +SetMarkerPath 59 4 88 +SetMarkerPath 59 5 89 +SetMarkerPath 59 6 87 +SetMarkerPath 59 7 245 +SetGoal 60 9 +SetZone 60 16 +SetMarkerPath 60 0 168 +SetMarkerPathFlags 60 0 j +SetMarkerPath 60 1 258 +SetMarkerPath 60 2 259 +SetMarkerPath 60 3 175 +SetZone 61 14 +SetMarkerPath 61 0 46 +SetMarkerPath 61 1 62 +SetZone 62 14 +SetMarkerPath 62 0 61 +SetMarkerPath 62 1 63 +SetZone 63 14 +SetMarkerPath 63 0 62 +SetMarkerPath 63 1 69 +SetMarkerPath 63 2 243 +SetMarkerPath 63 3 64 +SetZone 64 14 +SetMarkerPath 64 0 243 +SetMarkerPath 64 1 63 +SetMarkerPath 64 2 65 +SetZone 65 14 +SetMarkerPath 65 0 64 +SetMarkerPath 65 1 66 +SetMarkerPath 65 2 55 +SetZone 66 14 +SetMarkerPath 66 0 65 +SetMarkerPath 66 1 55 +SetMarkerPath 66 2 67 +SetZone 67 14 +SetMarkerPath 67 0 66 +SetMarkerPath 67 1 68 +SetZone 68 14 +SetMarkerPath 68 0 67 +SetMarkerPath 68 1 56 +SetZone 69 14 +SetMarkerPath 69 0 63 +SetMarkerPath 69 1 70 +SetZone 70 14 +SetMarkerPath 70 0 69 +SetMarkerPath 70 1 71 +SetZone 71 14 +SetMarkerPath 71 0 91 +SetMarkerPath 71 1 70 +SetMarkerPath 71 2 72 +SetZone 72 11 +SetMarkerPath 72 0 91 +SetMarkerPath 72 1 73 +SetMarkerPath 72 2 71 +SetZone 73 11 +SetMarkerPath 73 0 72 +SetMarkerPath 73 1 74 +SetZone 74 11 +SetMarkerPath 74 0 73 +SetMarkerPath 74 1 75 +SetMarkerPath 74 2 44 +SetZone 75 11 +SetMarkerPath 75 0 74 +SetMarkerPath 75 1 42 +SetMarkerPathFlags 75 1 j +SetZone 76 11 +SetMarkerPath 76 0 77 +SetMarkerPath 76 1 91 +SetMarkerPath 76 2 50 +SetMarkerPath 76 3 92 +SetZone 77 11 +SetMarkerPath 77 0 78 +SetMarkerPath 77 1 76 +SetMarkerPath 77 2 50 +SetMarkerPath 77 3 92 +SetZone 78 11 +SetMarkerPath 78 0 90 +SetMarkerPath 78 1 77 +SetMarkerPath 78 2 195 +SetZone 79 11 +SetMarkerPath 79 0 187 +SetMarkerPath 79 1 90 +SetMarkerPath 79 2 208 +SetZone 80 8 +SetMarkerPath 80 0 81 +SetMarkerPath 80 1 187 +SetMarkerPath 80 2 186 +SetZone 81 8 +SetMarkerPath 81 0 82 +SetMarkerPath 81 1 80 +SetZone 82 8 +SetMarkerPath 82 0 83 +SetMarkerPath 82 1 81 +SetZone 83 9 +SetMarkerPath 83 0 84 +SetMarkerPath 83 1 59 +SetMarkerPath 83 2 82 +SetZone 84 9 +SetMarkerPath 84 0 83 +SetMarkerPath 84 1 85 +SetMarkerPath 84 2 59 +SetZone 85 9 +SetMarkerPath 85 0 84 +SetMarkerPath 85 1 29 +SetMarkerPath 85 3 245 +SetZone 86 9 +SetMarkerPath 86 0 34 +SetMarkerPath 86 1 87 +SetMarkerPath 86 2 59 +SetMarkerPath 86 3 234 +SetZone 87 9 +SetMarkerPath 87 0 89 +SetMarkerPath 87 1 34 +SetMarkerPath 87 2 86 +SetMarkerPath 87 3 59 +SetZone 88 9 +SetMarkerPath 88 0 29 +SetMarkerPath 88 1 89 +SetMarkerPath 88 2 59 +SetMarkerPath 88 3 245 +SetZone 89 9 +SetMarkerPath 89 0 88 +SetMarkerPath 89 1 87 +SetMarkerPath 89 2 59 +SetZone 90 11 +SetMarkerPath 90 0 79 +SetMarkerPath 90 1 78 +SetMarkerPath 90 2 188 +SetZone 91 11 +SetMarkerPath 91 0 76 +SetMarkerPath 91 1 72 +SetMarkerPath 91 2 71 +SetMarkerPath 91 3 50 +SetZone 92 11 +SetMarkerPath 92 0 77 +SetMarkerPath 92 1 76 +SetMarkerPath 92 2 50 +SetMarkerPath 92 3 93 +SetZone 93 15 +SetMarkerPath 93 0 92 +SetMarkerPath 93 1 94 +SetZone 94 15 +SetMarkerPath 94 0 93 +SetMarkerPath 94 1 95 +SetZone 95 15 +SetMarkerPath 95 0 94 +SetMarkerPath 95 1 96 +SetZone 96 15 +SetMarkerPath 96 0 95 +SetMarkerPath 96 1 97 +SetMarkerPath 96 2 98 +SetZone 97 15 +SetMarkerPath 97 0 96 +SetMarkerPath 97 1 108 +SetZone 98 15 +SetMarkerPath 98 0 96 +SetMarkerPath 98 1 99 +SetZone 99 15 +SetMarkerPath 99 0 98 +SetMarkerPath 99 1 100 +SetZone 100 15 +SetMarkerPath 100 0 99 +SetMarkerPath 100 1 101 +SetZone 101 16 +SetMarkerPath 101 0 100 +SetMarkerPath 101 1 43 +SetMarkerPath 101 2 103 +SetZone 102 16 +SetMarkerPath 102 0 43 +SetMarkerPath 102 1 103 +SetMarkerPath 102 2 104 +SetMarkerPath 102 3 107 +SetMarkerPath 102 4 20 +SetZone 103 16 +SetMarkerPath 103 0 43 +SetMarkerPath 103 1 101 +SetMarkerPath 103 2 102 +SetMarkerPath 103 3 20 +SetZone 104 16 +SetMarkerPath 104 0 102 +SetMarkerPath 104 1 49 +SetMarkerPath 104 2 107 +SetMarkerPath 104 3 106 +SetZone 105 16 +SetMarkerPath 105 0 106 +SetMarkerPath 105 1 107 +SetZone 106 16 +SetMarkerPath 106 0 49 +SetMarkerPath 106 1 105 +SetMarkerPath 106 2 104 +SetZone 107 16 +SetMarkerPath 107 0 105 +SetMarkerPath 107 1 20 +SetMarkerPath 107 2 102 +SetMarkerPath 107 3 104 +SetZone 108 15 +SetMarkerPath 108 0 97 +SetMarkerPath 108 1 109 +SetZone 109 15 +SetMarkerPath 109 0 108 +SetMarkerPath 109 1 110 +SetMarkerPath 109 2 18 +SetMarkerPath 109 3 111 +SetZone 110 15 +SetMarkerPath 110 0 109 +SetMarkerPath 110 1 111 +SetMarkerPath 110 2 112 +SetZone 111 15 +SetMarkerPath 111 0 109 +SetMarkerPath 111 1 18 +SetMarkerPath 111 2 110 +SetZone 112 1 +SetMarkerPath 112 0 110 +SetMarkerPath 112 1 113 +SetZone 113 1 +SetMarkerPath 113 0 112 +SetMarkerPath 113 1 114 +SetMarkerPath 113 2 193 +SetMarkerPath 113 3 191 +SetMarkerPath 113 4 190 +SetMarkerPath 113 5 192 +SetZone 114 1 +SetMarkerPath 114 0 113 +SetMarkerPath 114 1 115 +SetMarkerPath 114 2 193 +SetMarkerPath 114 3 133 +SetMarkerPath 114 4 128 +SetMarkerPath 114 5 134 +SetZone 115 1 +SetMarkerPath 115 0 114 +SetMarkerPath 115 1 116 +SetMarkerPath 115 2 128 +SetMarkerPath 115 3 133 +SetMarkerPath 115 4 134 +SetZone 116 1 +SetMarkerPath 116 0 115 +SetMarkerPath 116 1 117 +SetMarkerPath 116 2 125 +SetMarkerPath 116 3 128 +SetMarkerPath 116 4 133 +SetZone 117 1 +SetMarkerPath 117 0 116 +SetMarkerPath 117 1 118 +SetZone 118 1 +SetMarkerPath 118 0 117 +SetMarkerPath 118 1 119 +SetZone 119 1 +SetMarkerPath 119 0 118 +SetMarkerPath 119 1 120 +SetZone 120 1 +SetMarkerPath 120 0 119 +SetMarkerPath 120 1 121 +SetZone 121 2 +SetMarkerPath 121 0 120 +SetMarkerPath 121 1 122 +SetMarkerPath 121 2 247 +SetMarkerPath 121 3 251 +SetZone 122 2 +SetMarkerPath 122 0 121 +SetMarkerPath 122 1 123 +SetZone 123 2 +SetMarkerPath 123 0 122 +SetMarkerPath 123 1 25 +SetMarkerPath 123 2 124 +SetZone 124 2 +SetMarkerPath 124 0 123 +SetZone 125 1 +SetMarkerPath 125 0 126 +SetMarkerPath 125 1 116 +SetZone 126 1 +SetMarkerPath 126 0 127 +SetMarkerPath 126 1 125 +SetMarkerPath 126 2 143 +SetZone 127 1 +SetMarkerPath 127 0 129 +SetMarkerPath 127 1 126 +SetZone 128 1 +SetMarkerPath 128 0 133 +SetMarkerPath 128 1 129 +SetMarkerPath 128 2 134 +SetMarkerPath 128 3 130 +SetZone 129 1 +SetMarkerPath 129 0 128 +SetMarkerPath 129 1 127 +SetZone 130 1 +SetMarkerPath 130 0 9 +SetMarkerPath 130 1 133 +SetMarkerPath 130 2 134 +SetMarkerPath 130 3 23 +SetMarkerPath 130 4 128 +SetZone 131 1 +SetMarkerPath 131 0 9 +SetMarkerPath 131 1 132 +SetMarkerPath 131 2 133 +SetMarkerPath 131 3 134 +SetMarkerPath 131 4 23 +SetZone 132 1 +SetMarkerPath 132 0 134 +SetMarkerPath 132 1 131 +SetMarkerPath 132 2 9 +SetMarkerPath 132 3 191 +SetZone 133 1 +SetMarkerPath 133 0 134 +SetMarkerPath 133 1 128 +SetMarkerPath 133 2 130 +SetMarkerPath 133 3 131 +SetZone 134 1 +SetMarkerPath 134 0 132 +SetMarkerPath 134 1 133 +SetMarkerPath 134 2 131 +SetMarkerPath 134 3 130 +SetMarkerPath 134 4 128 +SetMarkerPath 134 5 9 +SetZone 135 1 +SetMarkerPath 135 0 142 +SetMarkerPath 135 1 143 +SetZone 136 1 +SetMarkerPath 136 0 138 +SetMarkerPath 136 1 142 +SetZone 137 1 +SetMarkerPath 137 0 138 +SetMarkerPath 137 1 142 +SetZone 138 1 +SetMarkerPath 138 0 139 +SetMarkerPath 138 1 137 +SetMarkerPath 138 2 136 +SetZone 139 1 +SetMarkerPath 139 0 140 +SetMarkerPath 139 1 138 +SetZone 140 1 +SetMarkerPath 140 0 141 +SetMarkerPath 140 1 139 +SetMarkerPath 140 2 242 +SetZone 141 1 +SetMarkerPath 141 0 4 +SetMarkerPath 141 1 140 +SetMarkerPath 141 2 241 +SetMarkerPath 141 3 242 +SetZone 142 1 +SetMarkerPath 142 0 136 +SetMarkerPath 142 1 137 +SetMarkerPath 142 2 135 +SetZone 143 1 +SetMarkerPath 143 0 135 +SetMarkerPath 143 1 126 +SetMarkerPath 143 2 144 +SetZone 144 3 +SetMarkerPath 144 0 143 +SetMarkerPath 144 1 146 +SetZone 145 3 +SetMarkerPath 145 0 146 +SetMarkerPath 145 1 27 +SetMarkerPath 145 2 148 +SetZone 146 3 +SetMarkerPath 146 0 144 +SetMarkerPath 146 1 145 +SetMarkerPath 146 2 27 +SetZone 147 3 +SetMarkerPath 147 0 28 +SetMarkerPath 147 1 27 +SetZone 148 3 +SetMarkerPath 148 0 145 +SetMarkerPath 148 1 149 +SetMarkerPath 148 2 150 +SetZone 149 3 +SetMarkerPath 149 0 148 +SetMarkerPath 149 1 28 +SetMarkerPath 149 2 150 +SetZone 150 3 +SetMarkerPath 150 0 149 +SetMarkerPath 150 1 28 +SetMarkerPath 150 2 148 +SetMarkerPath 150 3 151 +SetZone 151 3 +SetMarkerPath 151 0 150 +SetMarkerPath 151 1 152 +SetZone 152 3 +SetMarkerPath 152 0 151 +SetMarkerPath 152 1 153 +SetMarkerPath 152 2 154 +SetMarkerPath 152 3 155 +SetZone 153 4 +SetMarkerPath 153 0 152 +SetMarkerPath 153 1 157 +SetMarkerPath 153 2 154 +SetZone 154 4 +SetMarkerPath 154 0 152 +SetMarkerPath 154 1 159 +SetMarkerPath 154 2 155 +SetMarkerPath 154 3 153 +SetZone 155 4 +SetMarkerPath 155 0 152 +SetMarkerPath 155 1 156 +SetMarkerPath 155 2 154 +SetZone 156 4 +SetMarkerPath 156 0 155 +SetMarkerPath 156 1 2 +SetZone 157 4 +SetMarkerPath 157 0 153 +SetMarkerPath 157 1 158 +SetZone 158 4 +SetMarkerPath 158 0 157 +SetMarkerPath 158 1 14 +SetZone 159 4 +SetMarkerPath 159 0 154 +SetMarkerPath 159 1 163 +SetZone 160 4 +SetMarkerPath 160 0 163 +SetMarkerPath 160 1 161 +SetMarkerPath 160 2 162 +SetMarkerPath 160 3 166 +SetZone 161 4 +SetMarkerPath 161 0 160 +SetMarkerPath 161 1 30 +SetZone 162 4 +SetMarkerPath 162 0 160 +SetMarkerPath 162 1 166 +SetMarkerPath 162 2 172 +SetZone 163 4 +SetMarkerPath 163 0 159 +SetMarkerPath 163 1 160 +SetMarkerPath 163 2 164 +SetMarkerPath 163 3 165 +SetZone 164 4 +SetMarkerPath 164 0 163 +SetMarkerPath 164 1 166 +SetZone 165 4 +SetMarkerPath 165 0 163 +SetMarkerPath 165 1 166 +SetZone 166 4 +SetMarkerPath 166 0 165 +SetMarkerPath 166 1 164 +SetMarkerPath 166 2 171 +SetMarkerPath 166 3 162 +SetMarkerPath 166 4 160 +SetMarkerPath 166 5 167 +SetZone 167 4 +SetMarkerPath 167 0 166 +SetMarkerPath 167 1 170 +SetMarkerPath 167 2 169 +SetMarkerPath 167 3 26 +SetMarkerPath 167 4 171 +SetZone 168 4 +SetMarkerPath 168 0 26 +SetMarkerPath 168 1 169 +SetZone 169 4 +SetMarkerPath 169 0 26 +SetMarkerPath 169 1 168 +SetMarkerPath 169 2 170 +SetMarkerPath 169 3 167 +SetZone 170 4 +SetMarkerPath 170 0 26 +SetMarkerPath 170 1 169 +SetMarkerPath 170 2 167 +SetZone 171 4 +SetMarkerPath 171 0 166 +SetMarkerPath 171 1 167 +SetZone 172 4 +SetMarkerPath 172 0 173 +SetMarkerPath 172 1 162 +SetZone 173 5 +SetMarkerPath 173 0 172 +SetMarkerPath 173 1 174 +SetZone 174 5 +SetMarkerPath 174 0 173 +SetMarkerPath 174 1 175 +SetMarkerPath 174 2 262 +SetZone 175 5 +SetMarkerPath 175 0 174 +SetMarkerPath 175 1 32 +SetMarkerPath 175 2 261 +SetZone 176 5 +SetMarkerPath 176 0 31 +SetMarkerPath 176 1 181 +SetMarkerPath 176 2 177 +SetZone 177 5 +SetMarkerPath 177 0 176 +SetMarkerPath 177 1 181 +SetMarkerPath 177 2 180 +SetMarkerPath 177 3 33 +SetZone 178 5 +SetMarkerPath 178 0 181 +SetMarkerPath 178 1 180 +SetMarkerPath 178 2 33 +SetZone 179 5 +SetMarkerPath 179 0 182 +SetMarkerPath 179 1 245 +SetZone 180 5 +SetMarkerPath 180 0 181 +SetMarkerPath 180 1 182 +SetMarkerPath 180 2 178 +SetMarkerPath 180 3 177 +SetMarkerPath 180 4 10 +SetMarkerPath 180 5 29 +SetZone 181 5 +SetMarkerPath 181 0 176 +SetMarkerPath 181 1 182 +SetMarkerPath 181 2 177 +SetMarkerPath 181 3 180 +SetMarkerPath 181 4 178 +SetZone 182 5 +SetMarkerPath 182 0 181 +SetMarkerPath 182 1 179 +SetMarkerPath 182 2 180 +SetZone 183 5 +SetMarkerPath 183 0 184 +SetZone 184 8 +SetMarkerPath 184 0 185 +SetMarkerPath 184 1 183 +SetZone 185 8 +SetMarkerPath 185 0 186 +SetMarkerPath 185 1 184 +SetMarkerPath 185 2 11 +SetZone 186 8 +SetMarkerPath 186 0 80 +SetMarkerPath 186 1 187 +SetMarkerPath 186 2 11 +SetMarkerPath 186 3 185 +SetZone 187 11 +SetMarkerPath 187 0 79 +SetMarkerPath 187 1 80 +SetMarkerPath 187 2 186 +SetMarkerPath 187 3 208 +SetZone 188 11 +SetMarkerPath 188 0 189 +SetMarkerPath 188 1 90 +SetZone 189 8 +SetMarkerPath 189 0 192 +SetMarkerPath 189 1 188 +SetMarkerPath 189 2 11 +SetZone 190 1 +SetMarkerPath 190 0 191 +SetMarkerPath 190 1 192 +SetZone 191 1 +SetMarkerPath 191 0 132 +SetMarkerPath 191 1 190 +SetZone 192 1 +SetMarkerPath 192 0 190 +SetMarkerPath 192 1 189 +SetZone 193 1 +SetMarkerPath 193 0 113 +SetMarkerPath 193 1 114 +SetMarkerPath 193 2 134 +SetMarkerPath 193 3 132 +SetMarkerPath 193 4 133 +SetMarkerPath 193 5 131 +SetZone 194 11 +SetMarkerPath 194 0 58 +SetMarkerPath 194 1 195 +SetZone 195 11 +SetMarkerPath 195 0 78 +SetMarkerPath 195 1 58 +SetMarkerPath 195 2 194 +SetZone 196 11 +SetMarkerPath 196 0 57 +SetMarkerPath 196 1 203 +SetMarkerPath 196 2 197 +SetZone 197 11 +SetMarkerPath 197 0 196 +SetMarkerPath 197 1 198 +SetMarkerPath 197 2 203 +SetZone 198 11 +SetMarkerPath 198 0 197 +SetMarkerPath 198 1 199 +SetZone 199 11 +SetMarkerPath 199 0 198 +SetMarkerPath 199 1 200 +SetZone 200 11 +SetMarkerPath 200 0 199 +SetMarkerPath 200 1 201 +SetMarkerPath 200 2 205 +SetZone 201 11 +SetMarkerPath 201 0 200 +SetMarkerPath 201 1 202 +SetMarkerPath 201 2 206 +SetMarkerPath 201 3 210 +SetMarkerPath 201 4 205 +SetZone 202 11 +SetMarkerPath 202 0 201 +SetMarkerPath 202 1 203 +SetMarkerPath 202 2 206 +SetMarkerPath 202 3 210 +SetMarkerPath 202 4 205 +SetZone 203 11 +SetMarkerPath 203 0 196 +SetMarkerPath 203 1 202 +SetMarkerPath 203 2 197 +SetZone 204 11 +SetMarkerPath 204 0 206 +SetMarkerPath 204 1 205 +SetMarkerPath 204 2 211 +SetZone 205 11 +SetMarkerPath 205 0 206 +SetMarkerPath 205 1 204 +SetMarkerPath 205 2 202 +SetMarkerPath 205 3 201 +SetMarkerPath 205 4 200 +SetZone 206 11 +SetMarkerPath 206 0 207 +SetMarkerPath 206 1 204 +SetMarkerPath 206 2 205 +SetMarkerPath 206 3 202 +SetMarkerPath 206 4 201 +SetZone 207 11 +SetMarkerPath 207 0 208 +SetMarkerPath 207 1 206 +SetMarkerPath 207 2 209 +SetZone 208 8 +SetMarkerPath 208 0 187 +SetMarkerPath 208 1 79 +SetMarkerPath 208 2 209 +SetMarkerPath 208 3 207 +SetZone 209 11 +SetMarkerPath 209 0 208 +SetMarkerPath 209 1 207 +SetMarkerPath 209 2 210 +SetZone 210 11 +SetMarkerPath 210 0 209 +SetMarkerPath 210 1 202 +SetMarkerPath 210 2 201 +SetZone 211 12 +SetMarkerPath 211 0 212 +SetMarkerPath 211 1 204 +SetZone 212 12 +SetMarkerPath 212 0 211 +SetMarkerPath 212 1 213 +SetMarkerPath 212 2 236 +SetMarkerPath 212 3 238 +SetZone 213 12 +SetMarkerPath 213 0 212 +SetMarkerPath 213 1 215 +SetMarkerPath 213 2 217 +SetZone 214 12 +SetMarkerPath 214 0 216 +SetMarkerPath 214 1 215 +SetMarkerPath 214 2 217 +SetMarkerPath 214 3 218 +SetZone 215 12 +SetMarkerPath 215 0 213 +SetMarkerPath 215 1 216 +SetMarkerPath 215 2 214 +SetZone 216 12 +SetMarkerPath 216 0 36 +SetMarkerPath 216 1 45 +SetMarkerPath 216 2 217 +SetMarkerPath 216 3 215 +SetMarkerPath 216 4 214 +SetZone 217 12 +SetMarkerPath 217 0 213 +SetMarkerPath 217 1 36 +SetMarkerPath 217 2 216 +SetMarkerPath 217 3 214 +SetZone 218 12 +SetMarkerPath 218 0 214 +SetMarkerPath 218 1 219 +SetZone 219 13 +SetMarkerPath 219 0 218 +SetMarkerPath 219 1 221 +SetMarkerPath 219 2 220 +SetZone 220 13 +SetMarkerPath 220 0 219 +SetMarkerPath 220 1 22 +SetMarkerPath 220 2 221 +SetZone 221 13 +SetMarkerPath 221 0 219 +SetMarkerPath 221 1 220 +SetMarkerPath 221 2 222 +SetZone 222 13 +SetMarkerPath 222 0 221 +SetMarkerPath 222 1 223 +SetMarkerPath 222 2 227 +SetZone 223 13 +SetMarkerPath 223 0 222 +SetMarkerPath 223 1 224 +SetMarkerPathFlags 223 1 j +SetMarkerPath 223 2 227 +SetZone 224 13 +SetMarkerPath 224 0 223 +SetMarkerPath 224 1 47 +SetMarkerPath 224 2 226 +SetZone 225 13 +SetMarkerPath 225 0 226 +SetMarkerPathFlags 225 0 j +SetMarkerPath 225 1 227 +SetZone 226 13 +SetMarkerPath 226 0 225 +SetMarkerPath 226 1 47 +SetMarkerPath 226 2 224 +SetZone 227 13 +SetMarkerPath 227 0 222 +SetMarkerPath 227 1 223 +SetMarkerPath 227 2 225 +SetMarkerPath 227 3 228 +SetMarkerPathFlags 227 3 wj +SetZone 228 13 +SetMarkerPath 228 0 227 +SetMarkerPath 228 1 229 +SetZone 229 10 +SetMarkerPath 229 0 48 +SetMarkerPath 229 1 230 +SetMarkerPath 229 2 228 +SetZone 230 10 +SetMarkerPath 230 0 39 +SetMarkerPath 230 1 48 +SetMarkerPath 230 2 229 +SetZone 231 10 +SetMarkerPath 231 0 235 +SetMarkerPath 231 1 48 +SetMarkerPath 231 2 232 +SetZone 232 10 +SetMarkerPath 232 0 233 +SetMarkerPath 232 1 231 +SetMarkerPath 232 2 38 +SetMarkerPath 232 3 37 +SetMarkerPath 232 4 237 +SetZone 233 10 +SetMarkerPath 233 0 234 +SetMarkerPath 233 1 232 +SetMarkerPath 233 2 37 +SetMarkerPath 233 3 38 +SetMarkerPath 233 4 237 +SetZone 234 10 +SetMarkerPath 234 0 86 +SetMarkerPathFlags 234 0 wj +SetMarkerPath 234 1 233 +SetZone 235 10 +SetMarkerPath 235 0 231 +SetZone 236 9 +SetMarkerPath 236 0 237 +SetMarkerPath 236 1 35 +SetZone 237 10 +SetMarkerPath 237 0 37 +SetMarkerPath 237 1 233 +SetMarkerPath 237 2 232 +SetMarkerPath 237 3 236 +SetMarkerPathFlags 237 3 wj +SetZone 238 9 +SetMarkerPath 238 0 236 +SetZone 239 10 +SetMarkerPath 239 0 240 +SetZone 240 10 +SetMarkerPath 240 0 38 +SetMarkerPath 240 1 232 +SetMarkerPath 240 2 233 +SetMarkerPath 240 3 237 +SetZone 241 1 +SetMarkerPath 241 0 4 +SetMarkerPath 241 1 242 +SetMarkerPath 241 2 141 +SetMarkerPath 241 3 9 +SetMarkerPath 241 4 23 +SetMarkerPath 241 5 132 +SetZone 242 1 +SetMarkerPath 242 0 241 +SetMarkerPath 242 1 141 +SetMarkerPath 242 2 140 +SetMarkerPath 242 3 23 +SetMarkerPath 242 4 9 +SetMarkerPath 242 5 131 +SetZone 243 14 +SetMarkerPath 243 0 63 +SetMarkerPath 243 1 64 +SetZone 244 14 +SetMarkerPath 244 0 56 +SetMarkerPath 244 1 42 +SetZone 245 9 +SetMarkerPath 245 0 59 +SetMarkerPath 245 1 10 +SetMarkerPath 245 2 29 +SetMarkerPath 245 3 88 +SetMarkerPath 245 4 85 +SetZone 246 2 +SetMarkerPath 246 0 251 +SetMarkerPath 246 1 252 +SetMarkerPath 246 2 253 +SetMarkerPath 246 3 254 +SetMarkerPath 246 4 23 +SetZone 247 2 +SetMarkerPath 247 0 248 +SetMarkerPath 247 1 121 +SetMarkerPath 247 2 251 +SetMarkerPath 247 3 252 +SetMarkerPath 247 4 253 +SetZone 248 2 +SetMarkerPath 248 0 249 +SetMarkerPath 248 1 247 +SetMarkerPath 248 2 253 +SetZone 249 2 +SetMarkerPath 249 0 250 +SetMarkerPath 249 1 248 +SetZone 250 2 +SetMarkerPath 250 0 249 +SetZone 251 2 +SetMarkerPath 251 0 121 +SetMarkerPath 251 1 246 +SetMarkerPath 251 2 252 +SetMarkerPath 251 3 247 +SetZone 252 2 +SetMarkerPath 252 0 251 +SetMarkerPath 252 1 247 +SetMarkerPath 252 2 253 +SetMarkerPath 252 3 246 +SetZone 253 2 +SetMarkerPath 253 0 247 +SetMarkerPath 253 1 248 +SetMarkerPath 253 2 12 +SetMarkerPath 253 3 252 +SetMarkerPath 253 4 246 +SetZone 254 2 +SetMarkerPath 254 0 242 +SetMarkerPathFlags 254 0 j +SetZone 255 5 +SetMarkerPath 255 0 262 +SetZone 256 5 +SetMarkerPath 256 0 257 +SetMarkerPath 256 1 263 +SetZone 257 5 +SetMarkerPath 257 0 260 +SetMarkerPath 257 1 256 +SetZone 258 5 +SetMarkerPath 258 0 259 +SetMarkerPath 258 1 261 +SetMarkerPath 258 2 262 +SetZone 259 5 +SetMarkerPath 259 0 260 +SetMarkerPath 259 1 258 +SetMarkerPath 259 2 262 +SetZone 260 5 +SetMarkerPath 260 0 257 +SetMarkerPath 260 1 259 +SetMarkerPath 260 2 262 +SetZone 261 5 +SetMarkerPath 261 0 258 +SetMarkerPath 261 1 175 +SetMarkerPath 261 2 32 +SetZone 262 5 +SetMarkerPath 262 0 174 +SetMarkerPath 262 1 260 +SetMarkerPath 262 2 259 +SetMarkerPath 262 3 258 +SetMarkerPath 262 4 255 +SetZone 263 6 +SetMarkerPath 263 0 256 +SetMarkerPath 263 1 264 +SetZone 264 6 +SetMarkerPath 264 0 263 +SetMarkerPath 264 1 265 +SetMarkerPath 264 2 51 +SetMarkerPath 264 3 285 +SetZone 265 6 +SetMarkerPath 265 0 264 +SetMarkerPath 265 1 266 +SetZone 266 6 +SetMarkerPath 266 0 265 +SetMarkerPath 266 1 267 +SetZone 267 6 +SetMarkerPath 267 0 266 +SetMarkerPath 267 1 268 +SetMarkerPath 267 2 24 +SetZone 268 6 +SetMarkerPath 268 0 267 +SetMarkerPath 268 1 269 +SetMarkerPath 268 2 24 +SetMarkerPath 268 3 270 +SetZone 269 6 +SetMarkerPath 269 0 268 +SetMarkerPath 269 1 24 +SetMarkerPath 269 2 270 +SetMarkerPath 269 3 278 +SetZone 270 6 +SetMarkerPath 270 0 271 +SetMarkerPath 270 1 268 +SetMarkerPath 270 2 269 +SetMarkerPath 270 3 272 +SetZone 271 6 +SetMarkerPath 271 0 270 +SetZone 272 6 +SetMarkerPath 272 0 273 +SetMarkerPath 272 1 270 +SetZone 273 6 +SetMarkerPath 273 0 274 +SetMarkerPath 273 1 272 +SetZone 274 6 +SetMarkerPath 274 0 275 +SetMarkerPath 274 1 273 +SetMarkerPath 274 2 288 +SetZone 275 6 +SetMarkerPath 275 0 276 +SetMarkerPath 275 1 274 +SetMarkerPath 275 2 288 +SetZone 276 6 +SetMarkerPath 276 0 277 +SetMarkerPath 276 1 275 +SetZone 277 6 +SetMarkerPath 277 0 13 +SetMarkerPath 277 1 276 +SetZone 278 6 +SetMarkerPath 278 0 269 +SetMarkerPath 278 1 279 +SetZone 279 6 +SetMarkerPath 279 0 278 +SetMarkerPath 279 1 280 +SetZone 280 6 +SetMarkerPath 280 0 279 +SetMarkerPath 280 1 281 +SetZone 281 7 +SetMarkerPath 281 0 282 +SetZone 282 7 +SetMarkerPath 282 0 281 +SetMarkerPath 282 1 283 +SetZone 283 7 +SetMarkerPath 283 0 282 +SetMarkerPath 283 1 1 +SetZone 284 7 +SetMarkerPath 284 0 1 +SetMarkerPath 284 1 26 +SetMarkerPath 284 2 168 +SetMarkerPath 284 3 167 +SetZone 285 6 +SetMarkerPath 285 0 264 +SetMarkerPath 285 1 286 +SetMarkerPath 285 2 53 +SetZone 286 6 +SetMarkerPath 286 0 285 +SetMarkerPath 286 1 53 +SetZone 287 6 +SetMarkerPath 287 0 52 +SetMarkerPath 287 1 54 +SetMarkerPath 287 2 288 +SetMarkerPath 287 3 26 +SetMarkerPath 287 4 167 +SetZone 288 6 +SetMarkerPath 288 0 54 +SetMarkerPath 288 1 274 +SetMarkerPath 288 2 275 +SetMarkerPath 288 3 287 +SetZone 289 7 +SetMarkerPath 289 2 206 From d2f6cc2f602afc022964b141a828dc7cf7af9fe9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Linus=20B=C3=A4ckman?= Date: Tue, 16 Sep 2025 20:44:01 +0200 Subject: [PATCH 18/34] Add bot support for map Metron --- .../example-configs/ktx/bots/maps/metron.bot | 705 ++++++++++++++++++ 1 file changed, 705 insertions(+) create mode 100644 resources/example-configs/ktx/bots/maps/metron.bot diff --git a/resources/example-configs/ktx/bots/maps/metron.bot b/resources/example-configs/ktx/bots/maps/metron.bot new file mode 100644 index 00000000..2263058b --- /dev/null +++ b/resources/example-configs/ktx/bots/maps/metron.bot @@ -0,0 +1,705 @@ +CreateMarker -905 -125 120 +CreateMarker -661 179 120 +CreateMarker -668 32 120 +CreateMarker -812 -40 120 +CreateMarker -950 19 120 +CreateMarker -864 -520 120 +CreateMarker -1017 -520 120 +CreateMarker -1018 -361 120 +CreateMarker -673 -252 120 +CreateMarker -671 -380 120 +CreateMarker -487 -385 120 +CreateMarker -486 -179 120 +CreateMarker -385 124 120 +CreateMarker -238 133 120 +CreateMarker -124 127 120 +CreateMarker -163 252 120 +CreateMarker -167 403 120 +CreateMarker -249 540 120 +CreateMarker 142 132 120 +CreateMarker 266 242 120 +CreateMarker 10 138 120 +CreateMarker 425 218 120 +CreateMarker 439 104 88 +CreateMarker 428 -14 24 +CreateMarker 295 -32 24 +CreateMarker 163 -75 24 +CreateMarker 24 -82 24 +CreateMarker -72 -87 24 +CreateMarker -176 -93 -8 +CreateMarker -307 -90 -8 +CreateMarker 31 -235 24 +CreateMarker 26 -353 24 +CreateMarker 17 -460 24 +CreateMarker 91 -675 24 +CreateMarker -131 -518 0 +CreateMarker -269 -514 -8 +CreateMarker -389 -511 -8 +CreateMarker -517 -509 -8 +CreateMarker -592 -371 -8 +CreateMarker -347 -206 -8 +CreateMarker -221 -190 -8 +CreateMarker -439 -279 -8 +CreateMarker -214 -649 -8 +CreateMarker -32 -667 24 +CreateMarker -639 -554 -8 +CreateMarker -640 -701 30 +CreateMarker -637 -820 56 +CreateMarker -485 -824 88 +CreateMarker -359 -832 120 +CreateMarker -346 -709 120 +CreateMarker -343 -583 120 +CreateMarker -340 -975 120 +CreateMarker -350 -1114 120 +CreateMarker -392 -1216 120 +CreateMarker -340 -1294 152 +CreateMarker -259 -1278 184 +CreateMarker -153 -1105 248 +CreateMarker -188 -999 264 +CreateMarker -178 -700 264 +CreateMarker -183 -832 264 +CreateMarker 43 -842 120 +CreateMarker -271 -835 120 +CreateMarker 271 -519 120 +CreateMarker 359 -469 120 +CreateMarker 311 -362 120 +CreateMarker 224 -285 120 +CreateMarker 116 -289 158 +CreateMarker -11 -289 222 +CreateMarker -154 -293 248 +CreateMarker -301 -298 248 +CreateMarker -444 -302 248 +CreateMarker -527 -212 248 +CreateMarker -532 -78 248 +CreateMarker -567 30 248 +CreateMarker -631 158 248 +CreateMarker -686 244 248 +CreateMarker -801 235 248 +CreateMarker -304 41 -8 +CreateMarker -334 165 -8 +CreateMarker -435 266 -8 +CreateMarker -536 298 -8 +CreateMarker -316 436 -8 +CreateMarker -502 431 -8 +CreateMarker -304 339 -8 +CreateMarker -768 360 -8 +CreateMarker -741 482 40 +CreateMarker -612 523 88 +CreateMarker -490 531 88 +CreateMarker -492 618 88 +CreateMarker -676 598 88 +CreateMarker -813 581 88 +CreateMarker -867 457 88 +CreateMarker -339 544 108 +CreateMarker -911 -238 88 +CreateMarker -898 -345 24 +CreateMarker -856 -435 -8 +CreateMarker -713 -429 -8 +CreateMarker -799 -275 -8 +CreateMarker -967 121 208 +CreateMarker -905 128 219 +SetZone 1 6 +SetMarkerPath 1 0 35 +SetZone 2 7 +SetMarkerPath 2 0 126 +SetMarkerPath 2 1 127 +SetMarkerPath 2 2 18 +SetGoal 3 1 +SetZone 3 1 +SetMarkerPath 3 0 55 +SetMarkerPath 3 1 56 +SetMarkerPath 3 2 53 +SetMarkerPath 3 3 61 +SetGoal 4 2 +SetZone 4 4 +SetMarkerPath 4 0 133 +SetMarkerPath 4 1 137 +SetMarkerPath 4 2 135 +SetGoal 5 3 +SetZone 5 5 +SetMarkerPath 5 0 71 +SetMarkerPath 5 1 72 +SetGoal 6 4 +SetZone 6 7 +SetMarkerPath 6 0 82 +SetMarkerPath 6 1 64 +SetMarkerPathFlags 6 1 j +SetMarkerPath 6 2 24 +SetMarkerPathFlags 6 2 j +SetMarkerPath 6 3 65 +SetMarkerPathFlags 6 3 j +SetMarkerPath 6 4 124 +SetMarkerPathFlags 6 4 j +SetMarkerPath 6 5 125 +SetMarkerPathFlags 6 5 j +SetMarkerPath 6 6 79 +SetMarkerPath 6 7 14 +SetGoal 7 5 +SetZone 7 6 +SetMarkerPath 7 0 115 +SetGoal 8 15 +SetZone 8 5 +SetMarkerPath 8 0 76 +SetMarkerPath 8 1 77 +SetGoal 9 15 +SetZone 9 7 +SetMarkerPath 9 0 123 +SetMarkerPath 9 1 124 +SetGoal 10 6 +SetZone 10 6 +SetMarkerPath 10 0 85 +SetMarkerPath 10 1 86 +SetMarkerPath 10 2 87 +SetMarkerPath 10 3 96 +SetGoal 11 18 +SetZone 11 4 +SetMarkerPath 11 0 144 +SetGoal 12 19 +SetZone 12 7 +SetMarkerPath 12 0 129 +SetMarkerPath 12 1 56 +SetMarkerPath 12 2 57 +SetGoal 13 16 +SetZone 13 1 +SetMarkerPath 13 0 40 +SetGoal 14 16 +SetZone 14 5 +SetMarkerPath 14 0 77 +SetGoal 15 19 +SetZone 15 6 +SetMarkerPath 15 0 117 +SetMarkerPath 15 1 118 +SetMarkerPath 15 2 116 +SetGoal 16 16 +SetZone 16 6 +SetMarkerPath 16 0 17 +SetMarkerPath 16 1 114 +SetGoal 17 16 +SetZone 17 6 +SetMarkerPath 17 0 113 +SetMarkerPath 17 1 16 +SetGoal 18 16 +SetZone 18 7 +SetMarkerPath 18 0 125 +SetGoal 19 16 +SetZone 19 4 +SetMarkerPath 19 0 70 +SetMarkerPath 19 1 20 +SetGoal 20 16 +SetZone 20 4 +SetMarkerPath 20 0 19 +SetMarkerPath 20 1 70 +SetMarkerPath 20 2 69 +SetGoal 21 18 +SetZone 21 3 +SetMarkerPath 21 0 93 +SetMarkerPath 21 1 94 +SetMarkerPath 21 2 92 +SetGoal 22 21 +SetZone 22 4 +SetMarkerPath 22 0 131 +SetMarkerPath 22 1 132 +SetMarkerPath 22 2 136 +SetGoal 23 23 +SetZone 23 5 +SetMarkerPath 23 0 82 +SetMarkerPath 23 1 65 +SetMarkerPath 23 2 24 +SetGoal 24 23 +SetZone 24 5 +SetMarkerPath 24 0 64 +SetMarkerPath 24 1 23 +SetGoal 25 20 +SetZone 25 2 +SetMarkerPath 25 0 94 +SetMarkerPath 25 1 91 +SetZone 26 1 +SetMarkerPath 26 0 3 +SetMarkerPath 26 1 56 +SetMarkerPath 26 2 55 +SetMarkerPath 26 3 61 +SetZone 27 6 +SetMarkerPath 27 0 1 +SetMarkerPath 27 1 35 +SetZone 28 5 +SetMarkerPath 28 0 74 +SetMarkerPath 28 1 72 +SetZone 29 4 +SetMarkerPath 29 0 20 +SetMarkerPath 29 1 70 +SetMarkerPath 29 2 69 +SetZone 30 7 +SetMarkerPath 30 0 126 +SetMarkerPath 30 1 18 +SetMarkerPath 30 2 127 +SetZone 31 5 +SetMarkerPath 31 0 63 +SetMarkerPath 31 1 103 +SetGoal 32 19 +SetZone 32 9 +SetMarkerPath 32 0 108 +SetMarkerPath 32 1 109 +SetZone 33 6 +SetMarkerPath 33 0 1 +SetMarkerPath 33 1 86 +SetZone 34 3 +SetMarkerPath 34 0 2 +SetMarkerPath 34 1 82 +SetGoal 35 18 +SetZone 35 6 +SetMarkerPath 35 0 113 +SetGoal 36 24 +SetZone 36 7 +SetMarkerPath 36 0 111 +SetMarkerPath 36 1 121 +SetMarkerPath 36 2 122 +SetMarkerPath 36 3 103 +SetMarkerPathFlags 36 3 j +SetGoal 37 23 +SetZone 37 6 +SetMarkerPath 37 0 88 +SetMarkerPath 37 1 39 +SetMarkerPath 37 2 89 +SetMarkerPath 37 3 95 +SetGoal 38 23 +SetZone 38 2 +SetMarkerPath 38 0 97 +SetMarkerPath 38 1 149 +SetMarkerPath 38 2 91 +SetGoal 39 24 +SetZone 39 6 +SetMarkerPath 39 0 88 +SetMarkerPath 39 1 37 +SetMarkerPath 39 2 89 +SetGoal 40 16 +SetZone 40 1 +SetMarkerPath 40 0 57 +SetMarkerPath 40 1 13 +SetMarkerPath 40 2 53 +SetGoal 41 7 +SetZone 41 9 +SetMarkerPath 41 0 51 +SetMarkerPath 41 1 105 +SetMarkerPath 41 2 106 +SetMarkerPath 41 3 50 +SetZone 42 9 +SetMarkerPath 42 0 106 +SetMarkerPath 42 1 105 +SetMarkerPath 42 2 104 +SetGoal 43 17 +SetZone 43 9 +SetMarkerPath 43 0 110 +SetMarkerPath 43 2 112 +SetZone 48 9 +SetZone 49 9 +SetGoal 50 15 +SetZone 50 9 +SetMarkerPath 50 0 51 +SetGoal 51 23 +SetZone 51 9 +SetMarkerPath 51 0 105 +SetMarkerPath 51 1 106 +SetMarkerPath 51 2 50 +SetZone 53 1 +SetMarkerPath 53 0 57 +SetMarkerPath 53 1 56 +SetMarkerPath 53 2 3 +SetMarkerPath 53 3 40 +SetMarkerPath 53 4 146 +SetZone 54 1 +SetMarkerPath 54 0 55 +SetMarkerPath 54 1 11 +SetMarkerPathFlags 54 1 j +SetMarkerPath 54 2 4 +SetZone 55 1 +SetMarkerPath 55 0 56 +SetMarkerPath 55 1 54 +SetMarkerPath 55 2 3 +SetZone 56 1 +SetMarkerPath 56 0 57 +SetMarkerPath 56 1 53 +SetMarkerPath 56 2 55 +SetMarkerPath 56 3 3 +SetZone 57 1 +SetMarkerPath 57 0 40 +SetMarkerPath 57 1 53 +SetMarkerPath 57 2 56 +SetZone 58 1 +SetMarkerPath 58 0 59 +SetMarkerPath 58 1 147 +SetZone 59 1 +SetMarkerPath 59 0 60 +SetZone 60 1 +SetMarkerPath 60 0 13 +SetZone 61 1 +SetMarkerPath 61 0 3 +SetMarkerPath 61 1 62 +SetZone 62 1 +SetMarkerPath 62 0 61 +SetMarkerPath 62 1 63 +SetMarkerPath 62 2 97 +SetMarkerPath 62 3 148 +SetZone 63 5 +SetMarkerPath 63 0 62 +SetMarkerPath 63 1 64 +SetMarkerPath 63 2 89 +SetMarkerPath 63 3 90 +SetMarkerPath 63 4 97 +SetZone 64 5 +SetMarkerPath 64 0 63 +SetMarkerPath 64 1 24 +SetMarkerPath 64 2 82 +SetZone 65 5 +SetMarkerPath 65 0 66 +SetMarkerPath 65 1 23 +SetZone 66 5 +SetMarkerPath 66 0 68 +SetMarkerPath 66 1 67 +SetMarkerPath 66 2 82 +SetMarkerPath 66 3 65 +SetZone 67 4 +SetMarkerPath 67 0 68 +SetMarkerPath 67 1 66 +SetMarkerPath 67 2 73 +SetZone 68 4 +SetMarkerPath 68 0 69 +SetMarkerPath 68 1 66 +SetMarkerPath 68 2 67 +SetZone 69 4 +SetMarkerPath 69 0 70 +SetMarkerPath 69 1 20 +SetMarkerPath 69 2 68 +SetMarkerPath 69 3 135 +SetMarkerPath 69 4 132 +SetZone 70 4 +SetMarkerPath 70 0 19 +SetMarkerPath 70 1 20 +SetMarkerPath 70 2 69 +SetMarkerPath 70 3 145 +SetZone 71 5 +SetMarkerPath 71 0 73 +SetMarkerPath 71 1 72 +SetMarkerPath 71 2 5 +SetZone 72 5 +SetMarkerPath 72 0 71 +SetMarkerPath 72 1 5 +SetMarkerPath 72 2 74 +SetZone 73 5 +SetMarkerPath 73 0 67 +SetMarkerPath 73 1 71 +SetZone 74 5 +SetMarkerPath 74 0 72 +SetMarkerPath 74 1 75 +SetZone 75 5 +SetMarkerPath 75 0 74 +SetMarkerPath 75 1 76 +SetZone 76 5 +SetMarkerPath 76 0 75 +SetMarkerPath 76 1 8 +SetMarkerPath 76 2 77 +SetZone 77 5 +SetMarkerPath 77 0 8 +SetMarkerPath 77 1 76 +SetMarkerPath 77 2 14 +SetMarkerPath 77 3 78 +SetZone 78 5 +SetMarkerPath 78 0 77 +SetMarkerPath 78 1 79 +SetZone 79 5 +SetMarkerPath 79 0 78 +SetMarkerPath 79 1 80 +SetMarkerPath 79 2 83 +SetZone 80 5 +SetMarkerPath 80 0 79 +SetMarkerPath 80 1 81 +SetZone 81 3 +SetMarkerPath 81 0 80 +SetMarkerPath 81 1 82 +SetMarkerPath 81 2 93 +SetZone 82 3 +SetMarkerPath 82 0 81 +SetMarkerPath 82 1 34 +SetMarkerPath 82 2 93 +SetMarkerPath 82 3 130 +SetZone 83 5 +SetMarkerPath 83 0 79 +SetMarkerPath 83 1 84 +SetZone 84 6 +SetMarkerPath 84 0 83 +SetMarkerPath 84 1 85 +SetZone 85 6 +SetMarkerPath 85 0 84 +SetMarkerPath 85 1 10 +SetZone 86 6 +SetMarkerPath 86 0 10 +SetMarkerPath 86 1 33 +SetMarkerPath 86 2 96 +SetZone 87 6 +SetMarkerPath 87 0 88 +SetMarkerPath 87 1 10 +SetMarkerPath 87 2 95 +SetMarkerPath 87 3 96 +SetZone 88 6 +SetMarkerPath 88 0 89 +SetMarkerPath 88 1 87 +SetMarkerPath 88 2 37 +SetMarkerPath 88 3 39 +SetMarkerPath 88 4 95 +SetZone 89 6 +SetMarkerPath 89 0 90 +SetMarkerPath 89 1 88 +SetMarkerPath 89 2 39 +SetMarkerPath 89 3 37 +SetZone 90 2 +SetMarkerPath 90 0 91 +SetMarkerPath 90 1 89 +SetMarkerPath 90 2 97 +SetMarkerPath 90 3 149 +SetZone 91 2 +SetMarkerPath 91 0 94 +SetMarkerPath 91 1 90 +SetMarkerPath 91 2 149 +SetMarkerPath 91 3 25 +SetMarkerPath 91 4 97 +SetMarkerPath 91 5 38 +SetZone 92 3 +SetMarkerPath 92 0 93 +SetMarkerPath 92 1 94 +SetMarkerPath 92 2 21 +SetZone 93 3 +SetMarkerPath 93 0 81 +SetMarkerPath 93 1 21 +SetMarkerPath 93 2 92 +SetMarkerPath 93 3 82 +SetZone 94 2 +SetMarkerPath 94 0 92 +SetMarkerPath 94 1 21 +SetMarkerPath 94 2 25 +SetMarkerPath 94 3 91 +SetZone 95 6 +SetMarkerPath 95 0 96 +SetMarkerPath 95 1 37 +SetMarkerPath 95 2 88 +SetMarkerPath 95 3 87 +SetZone 96 6 +SetMarkerPath 96 0 86 +SetMarkerPath 96 1 95 +SetMarkerPath 96 2 10 +SetMarkerPath 96 3 87 +SetZone 97 2 +SetMarkerPath 97 0 90 +SetMarkerPath 97 1 38 +SetMarkerPath 97 2 98 +SetMarkerPath 97 3 149 +SetMarkerPath 97 4 91 +SetZone 98 6 +SetMarkerPath 98 0 97 +SetMarkerPath 98 1 99 +SetZone 99 6 +SetMarkerPath 99 0 98 +SetMarkerPath 99 1 100 +SetZone 100 6 +SetMarkerPath 100 0 99 +SetMarkerPath 100 1 101 +SetZone 101 6 +SetMarkerPath 101 0 100 +SetMarkerPath 101 1 102 +SetMarkerPath 101 2 104 +SetMarkerPath 101 3 114 +SetZone 102 6 +SetMarkerPath 102 0 103 +SetMarkerPath 102 1 101 +SetMarkerPath 102 2 114 +SetZone 103 6 +SetMarkerPath 103 0 31 +SetMarkerPathFlags 103 0 j +SetMarkerPath 103 1 102 +SetZone 104 9 +SetMarkerPath 104 0 101 +SetMarkerPath 104 1 105 +SetMarkerPath 104 2 114 +SetZone 105 9 +SetMarkerPath 105 0 104 +SetMarkerPath 105 1 106 +SetMarkerPath 105 2 51 +SetZone 106 9 +SetMarkerPath 106 0 105 +SetMarkerPath 106 1 107 +SetMarkerPath 106 2 51 +SetZone 107 9 +SetMarkerPath 107 0 106 +SetMarkerPath 107 1 108 +SetZone 108 9 +SetMarkerPath 108 0 107 +SetMarkerPath 108 1 32 +SetZone 109 9 +SetMarkerPath 109 0 32 +SetMarkerPath 109 1 110 +SetZone 110 9 +SetMarkerPath 110 0 109 +SetMarkerPath 110 1 43 +SetZone 111 9 +SetMarkerPath 111 0 7 +SetMarkerPathFlags 111 0 j +SetMarkerPath 111 1 36 +SetMarkerPathFlags 111 1 j +SetMarkerPath 111 2 112 +SetZone 112 9 +SetMarkerPath 112 0 43 +SetMarkerPath 112 1 111 +SetMarkerPath 112 2 113 +SetZone 113 6 +SetMarkerPath 113 0 35 +SetMarkerPath 113 1 17 +SetZone 114 6 +SetMarkerPath 114 0 16 +SetMarkerPath 114 1 101 +SetMarkerPath 114 2 104 +SetMarkerPath 114 3 102 +SetZone 115 6 +SetMarkerPath 115 0 7 +SetMarkerPath 115 1 116 +SetZone 116 6 +SetMarkerPath 116 0 15 +SetMarkerPath 116 1 115 +SetMarkerPath 116 2 117 +SetZone 117 6 +SetMarkerPath 117 0 15 +SetMarkerPath 117 1 116 +SetMarkerPath 117 2 118 +SetZone 118 6 +SetMarkerPath 118 0 15 +SetMarkerPath 118 1 117 +SetMarkerPath 118 2 119 +SetZone 119 6 +SetMarkerPath 119 0 118 +SetMarkerPath 119 1 120 +SetZone 120 6 +SetMarkerPath 120 0 119 +SetMarkerPath 120 1 121 +SetZone 121 7 +SetMarkerPath 121 0 120 +SetMarkerPath 121 1 36 +SetMarkerPath 121 2 122 +SetZone 122 7 +SetMarkerPath 122 0 36 +SetMarkerPath 122 1 121 +SetMarkerPath 122 2 123 +SetZone 123 7 +SetMarkerPath 123 0 122 +SetMarkerPath 123 1 9 +SetMarkerPath 123 2 124 +SetZone 124 7 +SetMarkerPath 124 0 123 +SetMarkerPath 124 1 9 +SetMarkerPath 124 2 125 +SetZone 125 7 +SetMarkerPath 125 0 124 +SetMarkerPath 125 1 18 +SetMarkerPath 125 2 126 +SetZone 126 7 +SetMarkerPath 126 0 125 +SetMarkerPath 126 1 127 +SetZone 127 7 +SetMarkerPath 127 0 126 +SetMarkerPath 127 1 128 +SetZone 128 7 +SetMarkerPath 128 0 127 +SetMarkerPath 128 1 129 +SetZone 129 7 +SetMarkerPath 129 0 128 +SetMarkerPath 129 1 12 +SetZone 130 3 +SetMarkerPath 130 0 82 +SetMarkerPath 130 1 131 +SetZone 131 3 +SetMarkerPath 131 0 130 +SetMarkerPath 131 1 22 +SetZone 132 4 +SetMarkerPath 132 0 22 +SetMarkerPath 132 1 136 +SetMarkerPath 132 2 134 +SetMarkerPath 132 3 133 +SetZone 133 4 +SetMarkerPath 133 0 136 +SetMarkerPath 133 1 134 +SetMarkerPath 133 2 135 +SetMarkerPath 133 3 132 +SetMarkerPath 133 4 4 +SetZone 134 4 +SetMarkerPath 134 0 136 +SetMarkerPath 134 1 135 +SetMarkerPath 134 2 132 +SetMarkerPath 134 3 133 +SetZone 135 4 +SetMarkerPath 135 0 136 +SetMarkerPath 135 1 134 +SetMarkerPath 135 2 133 +SetMarkerPath 135 3 4 +SetZone 136 4 +SetMarkerPath 136 0 22 +SetMarkerPath 136 1 132 +SetMarkerPath 136 2 134 +SetMarkerPath 136 3 135 +SetMarkerPath 136 4 133 +SetZone 137 4 +SetMarkerPath 137 0 138 +SetMarkerPath 137 1 4 +SetZone 138 4 +SetMarkerPath 138 0 137 +SetMarkerPath 138 1 139 +SetZone 139 4 +SetMarkerPath 139 0 142 +SetMarkerPath 139 1 140 +SetMarkerPath 139 2 138 +SetZone 140 4 +SetMarkerPath 140 0 142 +SetMarkerPath 140 1 141 +SetMarkerPath 140 2 139 +SetMarkerPath 140 3 145 +SetMarkerPath 140 4 4 +SetMarkerPath 140 5 132 +SetZone 141 4 +SetMarkerPath 141 0 142 +SetMarkerPath 141 1 140 +SetZone 142 4 +SetMarkerPath 142 0 143 +SetMarkerPath 142 1 139 +SetMarkerPath 142 2 140 +SetMarkerPath 142 3 141 +SetZone 143 4 +SetMarkerPath 143 0 144 +SetMarkerPath 143 1 142 +SetZone 144 4 +SetMarkerPath 144 0 11 +SetMarkerPath 144 1 143 +SetZone 145 4 +SetMarkerPath 145 0 140 +SetMarkerPath 145 1 70 +SetMarkerPath 145 2 135 +SetMarkerPath 145 3 136 +SetZone 146 1 +SetMarkerPath 146 0 147 +SetMarkerPath 146 1 53 +SetZone 147 1 +SetMarkerPath 147 0 148 +SetMarkerPath 147 1 146 +SetZone 148 1 +SetMarkerPath 148 0 147 +SetMarkerPath 148 1 149 +SetZone 149 2 +SetMarkerPath 149 0 148 +SetMarkerPath 149 1 38 +SetMarkerPath 149 2 97 +SetMarkerPath 149 3 90 +SetMarkerPath 149 4 91 +SetZone 150 2 +SetMarkerPath 150 0 148 +SetMarkerPath 150 1 149 +SetMarkerPath 150 2 91 +SetZone 151 1 +SetMarkerPath 151 0 57 +SetZone 152 1 +SetMarkerPath 152 0 57 +SetMarkerPath 152 1 56 +SetMarkerPath 152 2 55 From 03fbb5e54df457be17d6e26ba7fcbaa946adba11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Linus=20B=C3=A4ckman?= Date: Tue, 16 Sep 2025 20:44:14 +0200 Subject: [PATCH 19/34] Add bot support for map Pocket --- .../example-configs/ktx/bots/maps/pocket.bot | 628 ++++++++++++++++++ 1 file changed, 628 insertions(+) create mode 100644 resources/example-configs/ktx/bots/maps/pocket.bot diff --git a/resources/example-configs/ktx/bots/maps/pocket.bot b/resources/example-configs/ktx/bots/maps/pocket.bot new file mode 100644 index 00000000..abc81699 --- /dev/null +++ b/resources/example-configs/ktx/bots/maps/pocket.bot @@ -0,0 +1,628 @@ +CreateMarker -676 -230 196 +CreateMarker -535 -234 236 +CreateMarker -407 -251 256 +CreateMarker -272 -394 256 +CreateMarker -279 -515 256 +CreateMarker -285 -707 328 +CreateMarker -387 -880 328 +CreateMarker -659 -353 196 +CreateMarker -554 -460 196 +CreateMarker -510 -577 196 +CreateMarker -500 -720 196 +CreateMarker -502 -834 196 +CreateMarker -505 -953 148 +CreateMarker -506 -1058 148 +CreateMarker -605 -725 172 +CreateMarker -606 -589 172 +CreateMarker -752 -443 172 +CreateMarker -789 -207 172 +CreateMarker -789 -356 172 +CreateMarker -822 -623 160 +CreateMarker -765 -744 160 +CreateMarker -429 -715 196 +CreateMarker -718 -704 312 +CreateMarker -474 -826 332 +CreateMarker -151 -275 256 +CreateMarker -8 -280 292 +CreateMarker 143 -314 292 +CreateMarker 256 -200 292 +CreateMarker 196 -57 292 +CreateMarker 202 95 292 +CreateMarker 201 280 256 +CreateMarker 317 482 256 +CreateMarker 334 332 256 +CreateMarker 591 144 256 +CreateMarker 556 341 256 +CreateMarker 467 360 256 +CreateMarker -283 -256 256 +CreateMarker 238 410 256 +CreateMarker 459 528 224 +CreateMarker 531 671 244 +CreateMarker 620 478 220 +CreateMarker 708 359 220 +CreateMarker 709 152 172 +CreateMarker 712 11 104 +CreateMarker 713 -115 88 +CreateMarker 799 -222 88 +CreateMarker 636 -262 64 +CreateMarker 718 -374 64 +CreateMarker 569 -537 64 +CreateMarker 437 -659 28 +CreateMarker 244 -850 28 +CreateMarker 125 -863 12 +CreateMarker 449 793 248 +CreateMarker 183 747 316 +CreateMarker 92 621 316 +CreateMarker 133 462 316 +CreateMarker 545 511 220 +CreateMarker 708 271 220 +CreateMarker 519 -203 64 +CreateMarker 403 -100 88 +CreateMarker 262 -97 88 +CreateMarker 100 -93 88 +CreateMarker -45 -91 64 +CreateMarker -152 -157 64 +CreateMarker -249 -73 64 +CreateMarker -251 41 64 +CreateMarker -415 77 108 +CreateMarker -529 77 164 +CreateMarker -615 80 196 +CreateMarker 14 -676 -4 +CreateMarker 126 -649 -4 +CreateMarker 211 -539 -4 +CreateMarker 272 -383 16 +CreateMarker 200 -243 4 +CreateMarker 349 -274 52 +CreateMarker 351 -416 52 +CreateMarker 347 -539 52 +CreateMarker 250 -640 52 +CreateMarker 348 -206 88 +CreateMarker 114 -530 52 +CreateMarker 164 -435 52 +CreateMarker 164 -328 52 +CreateMarker 73 -409 52 +CreateMarker -19 -507 52 +CreateMarker -114 -607 52 +CreateMarker -244 -589 52 +CreateMarker -273 -309 64 +CreateMarker 395 -566 300 +CreateMarker 287 -732 300 +CreateMarker 40 -622 52 +SetZone 1 6 +SetMarkerPath 1 0 110 +SetMarkerPath 1 1 41 +SetZone 2 4 +SetMarkerPath 2 0 84 +SetMarkerPath 2 1 97 +SetZone 3 1 +SetMarkerPath 3 0 57 +SetMarkerPath 3 1 44 +SetMarkerPath 4 0 6 +SetMarkerPath 4 1 44 +SetZone 5 1 +SetMarkerPath 5 0 51 +SetMarkerPath 5 1 50 +SetZone 6 5 +SetMarkerPath 6 0 39 +SetMarkerPath 6 1 38 +SetZone 7 2 +SetMarkerPath 7 0 72 +SetGoal 8 23 +SetZone 8 5 +SetMarkerPath 8 0 92 +SetMarkerPath 8 1 90 +SetMarkerPath 8 2 15 +SetGoal 9 15 +SetZone 9 5 +SetMarkerPath 9 0 91 +SetMarkerPath 9 1 93 +SetMarkerPath 9 2 92 +SetMarkerPath 9 3 103 +SetMarkerPath 9 4 11 +SetGoal 10 1 +SetZone 10 4 +SetMarkerPath 10 0 99 +SetMarkerPath 10 1 100 +SetGoal 11 18 +SetZone 11 5 +SetMarkerPath 11 0 93 +SetMarkerPath 11 1 9 +SetMarkerPath 11 2 103 +SetMarkerPath 11 3 91 +SetZone 12 5 +SetMarkerPath 12 0 5 +SetMarkerPath 12 1 38 +SetGoal 13 19 +SetZone 13 6 +SetMarkerPath 13 0 134 +SetMarkerPathFlags 13 0 j +SetMarkerPath 13 1 39 +SetMarkerPath 13 2 56 +SetGoal 14 24 +SetZone 14 4 +SetMarkerPath 14 0 101 +SetMarkerPath 14 1 85 +SetMarkerPath 14 2 86 +SetZone 15 5 +SetMarkerPath 15 0 7 +SetMarkerPath 15 1 8 +SetGoal 16 2 +SetZone 16 5 +SetMarkerPath 16 0 104 +SetMarkerPath 16 1 105 +SetMarkerPath 16 2 106 +SetMarkerPath 18 0 20 +SetGoal 19 3 +SetZone 19 7 +SetMarkerPath 19 0 20 +SetMarkerPath 19 1 28 +SetMarkerPath 19 2 33 +SetMarkerPath 19 3 71 +SetMarkerPath 19 4 72 +SetMarkerPath 19 5 116 +SetMarkerPath 19 6 117 +SetMarkerPath 19 7 120 +SetZone 20 7 +SetMarkerPath 20 0 19 +SetGoal 21 4 +SetZone 21 4 +SetMarkerPath 21 0 77 +SetMarkerPath 21 1 80 +SetMarkerPath 21 2 78 +SetGoal 22 21 +SetZone 22 5 +SetMarkerPath 22 0 94 +SetMarkerPath 22 1 95 +SetMarkerPath 22 2 122 +SetMarkerPath 22 3 121 +SetGoal 23 20 +SetZone 23 1 +SetMarkerPath 23 0 51 +SetMarkerPath 23 1 68 +SetMarkerPath 23 2 27 +SetMarkerPath 23 3 55 +SetGoal 24 5 +SetZone 24 6 +SetMarkerPath 24 0 130 +SetMarkerPath 24 1 42 +SetMarkerPath 24 2 131 +SetZone 25 6 +SetMarkerPath 25 0 126 +SetMarkerPath 25 1 125 +SetMarkerPath 25 2 124 +SetMarkerPath 25 3 127 +SetMarkerPath 25 4 128 +SetGoal 26 6 +SetZone 26 1 +SetMarkerPath 26 0 55 +SetMarkerPathFlags 26 0 j +SetMarkerPath 26 1 54 +SetMarkerPathFlags 26 1 j +SetMarkerPath 26 2 53 +SetMarkerPathFlags 26 2 j +SetMarkerPath 26 3 67 +SetGoal 27 18 +SetZone 27 1 +SetMarkerPath 27 0 66 +SetGoal 28 17 +SetZone 28 2 +SetMarkerPath 28 0 70 +SetMarkerPath 28 1 71 +SetMarkerPath 28 2 72 +SetMarkerPath 28 3 73 +SetGoal 30 16 +SetZone 30 4 +SetMarkerPath 30 0 97 +SetMarkerPath 30 1 98 +SetZone 31 5 +SetMarkerPath 31 0 8 +SetMarkerPath 31 1 93 +SetMarkerPath 31 2 9 +SetMarkerPath 31 3 92 +SetGoal 32 23 +SetZone 32 4 +SetMarkerPath 32 0 75 +SetGoal 33 19 +SetZone 33 3 +SetMarkerPath 33 0 71 +SetMarkerPath 33 1 125 +SetMarkerPath 33 2 117 +SetGoal 34 23 +SetZone 34 1 +SetMarkerPath 34 0 43 +SetMarkerPath 34 1 45 +SetGoal 35 16 +SetZone 35 4 +SetMarkerPath 35 0 98 +SetMarkerPath 35 1 99 +SetGoal 36 24 +SetZone 36 1 +SetMarkerPath 36 0 66 +SetGoal 37 24 +SetZone 37 6 +SetMarkerPath 37 0 131 +SetMarkerPath 37 1 108 +SetMarkerPath 37 2 109 +SetGoal 38 16 +SetZone 38 5 +SetMarkerPath 38 0 6 +SetMarkerPath 38 1 12 +SetGoal 39 16 +SetZone 39 5 +SetMarkerPath 39 0 96 +SetMarkerPath 39 1 6 +SetGoal 40 16 +SetZone 40 6 +SetMarkerPath 40 0 41 +SetMarkerPath 40 1 111 +SetGoal 41 16 +SetZone 41 6 +SetMarkerPath 41 0 40 +SetGoal 42 18 +SetZone 42 6 +SetMarkerPath 42 0 24 +SetGoal 43 7 +SetZone 43 1 +SetMarkerPath 43 0 113 +SetMarkerPath 43 1 34 +SetGoal 44 16 +SetZone 44 1 +SetMarkerPath 44 0 58 +SetMarkerPath 44 1 4 +SetZone 45 1 +SetMarkerPath 45 0 46 +SetMarkerPath 45 1 52 +SetMarkerPath 45 2 34 +SetZone 46 1 +SetMarkerPath 46 0 47 +SetMarkerPath 46 1 45 +SetZone 47 1 +SetMarkerPath 47 0 48 +SetMarkerPath 47 1 46 +SetMarkerPath 47 2 81 +SetZone 48 1 +SetMarkerPath 48 0 49 +SetMarkerPath 48 1 47 +SetMarkerPath 48 2 69 +SetMarkerPath 48 3 81 +SetZone 49 1 +SetMarkerPath 49 0 50 +SetMarkerPath 49 1 48 +SetZone 50 1 +SetMarkerPath 50 0 51 +SetMarkerPath 50 1 49 +SetMarkerPath 50 2 27 +SetZone 51 1 +SetMarkerPath 51 0 23 +SetMarkerPath 51 1 50 +SetMarkerPath 51 2 27 +SetZone 52 1 +SetMarkerPath 52 0 45 +SetMarkerPath 52 1 53 +SetMarkerPath 52 2 26 +SetMarkerPathFlags 52 2 r +SetRocketJumpPathFields 52 2 56.0 75.0 2 +SetZone 53 1 +SetMarkerPath 53 0 52 +SetMarkerPath 53 1 54 +SetZone 54 1 +SetMarkerPath 54 0 53 +SetMarkerPath 54 1 55 +SetMarkerPath 54 2 66 +SetMarkerPath 54 3 26 +SetMarkerPathFlags 54 3 r +SetRocketJumpPathFields 54 3 80.0 215.0 10 +SetZone 55 1 +SetMarkerPath 55 0 54 +SetMarkerPath 55 1 56 +SetMarkerPath 55 2 66 +SetZone 56 1 +SetMarkerPath 56 0 55 +SetMarkerPath 56 1 57 +SetMarkerPath 56 2 66 +SetZone 57 1 +SetMarkerPath 57 0 56 +SetMarkerPath 57 1 58 +SetZone 58 1 +SetMarkerPath 58 0 57 +SetMarkerPath 58 1 44 +SetZone 59 1 +SetMarkerPath 59 0 55 +SetMarkerPathFlags 59 0 j +SetZone 60 1 +SetMarkerPath 60 0 54 +SetMarkerPathFlags 60 0 j +SetZone 61 1 +SetMarkerPath 61 0 52 +SetMarkerPathFlags 61 0 j +SetZone 62 1 +SetMarkerPath 62 0 45 +SetMarkerPathFlags 62 0 j +SetZone 63 1 +SetMarkerPath 63 0 52 +SetMarkerPathFlags 63 0 j +SetZone 64 1 +SetMarkerPath 64 0 61 +SetMarkerPath 64 1 60 +SetZone 65 1 +SetMarkerPath 65 0 59 +SetMarkerPath 65 1 60 +SetZone 66 1 +SetMarkerPath 66 0 54 +SetMarkerPath 66 1 55 +SetMarkerPath 66 2 56 +SetMarkerPath 66 3 36 +SetMarkerPathFlags 66 3 j +SetMarkerPath 66 4 27 +SetMarkerPathFlags 66 4 j +SetZone 67 1 +SetMarkerPath 67 1 26 +SetZone 68 1 +SetMarkerPath 68 0 67 +SetMarkerPathFlags 68 0 j +SetMarkerPath 68 3 27 +SetZone 69 1 +SetMarkerPath 69 0 48 +SetMarkerPath 69 1 81 +SetMarkerPath 69 2 70 +SetZone 70 2 +SetMarkerPath 70 0 69 +SetMarkerPath 70 1 28 +SetMarkerPath 70 2 71 +SetZone 71 2 +SetMarkerPath 71 0 70 +SetMarkerPath 71 1 28 +SetMarkerPath 71 2 72 +SetMarkerPath 71 3 33 +SetMarkerPathFlags 71 3 j +SetZone 72 2 +SetMarkerPath 72 0 71 +SetMarkerPath 72 1 73 +SetMarkerPath 72 2 28 +SetZone 73 2 +SetMarkerPath 73 0 72 +SetMarkerPath 73 1 28 +SetMarkerPath 73 2 74 +SetZone 74 2 +SetMarkerPath 74 0 73 +SetMarkerPath 74 1 75 +SetZone 75 4 +SetMarkerPath 75 0 74 +SetMarkerPath 75 1 77 +SetMarkerPath 75 3 32 +SetMarkerPath 75 4 82 +SetZone 76 4 +SetMarkerPath 76 0 83 +SetMarkerPath 76 1 82 +SetZone 77 4 +SetMarkerPath 77 0 75 +SetMarkerPath 77 1 82 +SetMarkerPath 77 2 80 +SetMarkerPath 77 3 21 +SetZone 78 4 +SetMarkerPath 78 0 21 +SetMarkerPath 78 1 79 +SetMarkerPath 78 2 87 +SetMarkerPath 78 3 86 +SetZone 79 4 +SetMarkerPath 79 0 80 +SetMarkerPath 79 1 78 +SetMarkerPath 79 2 87 +SetMarkerPath 79 3 86 +SetMarkerPath 79 4 101 +SetMarkerPath 79 5 85 +SetMarkerPath 79 6 102 +SetZone 80 4 +SetMarkerPath 80 0 77 +SetMarkerPath 80 1 79 +SetMarkerPath 80 2 21 +SetMarkerPath 80 3 101 +SetMarkerPath 80 4 85 +SetMarkerPath 80 5 83 +SetZone 81 1 +SetMarkerPath 81 0 69 +SetMarkerPath 81 1 47 +SetMarkerPath 81 2 48 +SetZone 82 4 +SetMarkerPath 82 0 75 +SetMarkerPath 82 1 76 +SetMarkerPath 82 2 77 +SetZone 83 4 +SetMarkerPath 83 0 76 +SetMarkerPath 83 1 101 +SetMarkerPath 83 2 84 +SetZone 84 4 +SetMarkerPath 84 0 83 +SetMarkerPath 84 1 97 +SetMarkerPath 84 2 101 +SetZone 85 4 +SetMarkerPath 85 0 101 +SetMarkerPath 85 1 14 +SetMarkerPath 85 2 86 +SetZone 86 4 +SetMarkerPath 86 0 14 +SetMarkerPath 86 1 102 +SetMarkerPath 86 2 85 +SetZone 87 4 +SetMarkerPath 87 0 102 +SetMarkerPath 87 1 88 +SetZone 88 5 +SetMarkerPath 88 0 87 +SetMarkerPath 88 1 89 +SetZone 89 5 +SetMarkerPath 89 0 88 +SetMarkerPath 89 1 90 +SetMarkerPath 89 2 91 +SetMarkerPath 89 3 103 +SetZone 90 5 +SetMarkerPath 90 0 89 +SetMarkerPath 90 1 8 +SetZone 91 5 +SetMarkerPath 91 0 89 +SetMarkerPath 91 1 9 +SetMarkerPath 91 2 92 +SetMarkerPath 91 3 103 +SetMarkerPath 91 4 11 +SetZone 92 5 +SetMarkerPath 92 0 91 +SetMarkerPath 92 1 9 +SetMarkerPath 92 2 8 +SetZone 93 5 +SetMarkerPath 93 0 9 +SetMarkerPath 93 1 11 +SetMarkerPath 93 2 94 +SetMarkerPath 93 3 121 +SetZone 94 5 +SetMarkerPath 94 0 93 +SetMarkerPath 94 1 22 +SetMarkerPath 94 2 121 +SetZone 95 5 +SetMarkerPath 95 0 22 +SetMarkerPath 95 1 96 +SetZone 96 5 +SetMarkerPath 96 0 95 +SetMarkerPath 96 1 39 +SetZone 97 4 +SetMarkerPath 97 0 84 +SetMarkerPath 97 1 30 +SetZone 98 4 +SetMarkerPath 98 0 30 +SetMarkerPath 98 1 35 +SetMarkerPath 98 2 99 +SetZone 99 4 +SetMarkerPath 99 0 35 +SetMarkerPath 99 1 98 +SetMarkerPath 99 2 10 +SetZone 100 4 +SetMarkerPath 100 0 10 +SetMarkerPath 100 1 32 +SetMarkerPath 100 2 82 +SetMarkerPath 100 3 76 +SetZone 101 4 +SetMarkerPath 101 0 83 +SetMarkerPath 101 1 84 +SetMarkerPath 101 2 85 +SetMarkerPath 101 3 14 +SetZone 102 4 +SetMarkerPath 102 0 86 +SetMarkerPath 102 1 87 +SetZone 103 5 +SetMarkerPath 103 0 89 +SetMarkerPath 103 1 91 +SetMarkerPath 103 2 9 +SetMarkerPath 103 3 11 +SetMarkerPath 103 4 104 +SetZone 104 5 +SetMarkerPath 104 0 105 +SetMarkerPath 104 1 103 +SetMarkerPath 104 2 16 +SetZone 105 5 +SetMarkerPath 105 0 106 +SetMarkerPath 105 1 104 +SetMarkerPath 105 2 123 +SetMarkerPath 105 3 16 +SetZone 106 5 +SetMarkerPath 106 0 107 +SetMarkerPath 106 1 105 +SetMarkerPath 106 2 16 +SetZone 107 5 +SetMarkerPath 107 0 108 +SetMarkerPath 107 1 106 +SetZone 108 6 +SetMarkerPath 108 0 37 +SetMarkerPath 108 1 131 +SetMarkerPath 108 2 109 +SetMarkerPath 108 3 107 +SetZone 109 6 +SetMarkerPath 109 0 108 +SetMarkerPath 109 1 37 +SetMarkerPath 109 2 110 +SetZone 110 6 +SetMarkerPath 110 0 109 +SetMarkerPath 110 1 111 +SetZone 111 6 +SetMarkerPath 111 0 110 +SetMarkerPath 111 1 40 +SetMarkerPath 111 2 112 +SetZone 112 1 +SetMarkerPath 112 0 111 +SetMarkerPath 112 1 113 +SetZone 113 1 +SetMarkerPath 113 0 112 +SetMarkerPath 113 1 43 +SetZone 114 6 +SetMarkerPath 114 0 115 +SetZone 115 6 +SetMarkerPath 115 0 116 +SetZone 116 6 +SetMarkerPath 116 0 117 +SetZone 117 6 +SetMarkerPath 117 0 119 +SetZone 118 6 +SetMarkerPath 118 0 119 +SetZone 119 6 +SetMarkerPath 119 0 123 +SetMarkerPathFlags 119 0 j +SetMarkerPath 119 1 120 +SetZone 120 6 +SetMarkerPath 120 0 121 +SetMarkerPath 120 1 119 +SetZone 121 5 +SetMarkerPath 121 0 22 +SetMarkerPath 121 1 122 +SetMarkerPath 121 2 120 +SetMarkerPath 121 3 94 +SetMarkerPath 121 4 93 +SetZone 122 5 +SetMarkerPath 122 0 22 +SetMarkerPath 122 1 121 +SetMarkerPath 122 2 124 +SetMarkerPathFlags 122 2 j +SetMarkerPath 122 3 125 +SetMarkerPathFlags 122 3 j +SetZone 123 5 +SetMarkerPath 123 0 119 +SetMarkerPath 123 1 105 +SetZone 124 6 +SetMarkerPath 124 0 122 +SetMarkerPath 124 1 125 +SetMarkerPath 124 2 127 +SetMarkerPath 124 3 134 +SetZone 125 6 +SetMarkerPath 125 0 122 +SetMarkerPath 125 1 124 +SetMarkerPath 125 2 126 +SetMarkerPath 125 3 127 +SetZone 126 6 +SetMarkerPath 126 0 119 +SetMarkerPath 126 1 125 +SetMarkerPath 126 2 127 +SetZone 127 6 +SetMarkerPath 127 0 126 +SetMarkerPath 127 1 125 +SetMarkerPath 127 2 124 +SetMarkerPath 127 3 128 +SetZone 128 6 +SetMarkerPath 128 0 127 +SetMarkerPath 128 1 129 +SetMarkerPath 128 2 134 +SetZone 129 6 +SetMarkerPath 129 0 128 +SetMarkerPath 129 1 130 +SetMarkerPath 129 2 134 +SetZone 130 6 +SetMarkerPath 130 0 129 +SetMarkerPath 130 1 24 +SetZone 131 6 +SetMarkerPath 131 0 24 +SetMarkerPath 131 1 37 +SetMarkerPath 131 2 108 +SetZone 132 3 +SetMarkerPath 132 0 33 +SetZone 133 3 +SetMarkerPath 133 0 33 +SetZone 134 6 +SetMarkerPath 134 0 13 +SetMarkerPath 134 1 124 +SetMarkerPath 134 2 128 +SetMarkerPath 134 3 129 From 107e703e9f6fc131d32e8c5f9a2eb8b93c481fd0 Mon Sep 17 00:00:00 2001 From: riovv Date: Fri, 26 Sep 2025 19:21:53 +0200 Subject: [PATCH 20/34] Update cmake min version requirement to 3.10 Compatibility with CMake < 3.10 will be removed from a future version of CMake. Updating the min version in advance. --- CMakeLists.txt | 2 +- tools/q3asm/CMakeLists.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6d54d486..d8d31195 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.9.0) +cmake_minimum_required(VERSION 3.10.0) # Set project name and languge. project(qwprogs C) diff --git a/tools/q3asm/CMakeLists.txt b/tools/q3asm/CMakeLists.txt index c7acb754..88ef9203 100644 --- a/tools/q3asm/CMakeLists.txt +++ b/tools/q3asm/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.9.0) +cmake_minimum_required(VERSION 3.10.0) project(q3asm C) add_executable(q3asm q3asm.c q3vm.c cmdlib.c) From 2628185ef842151c4b06608a8a3d815b82fabef6 Mon Sep 17 00:00:00 2001 From: dusty-qw <71472647+dusty-qw@users.noreply.github.com> Date: Sat, 11 Oct 2025 00:07:23 -0700 Subject: [PATCH 21/34] PREWAR: q3 style prewar with k_prewar 3 --- resources/example-configs/ktx/ktx.cfg | 2 +- src/admin.c | 42 +++++++++++++++++++++++++-- src/client.c | 23 +++++++++++++-- src/combat.c | 37 ++++++++++++++++++----- src/commands.c | 4 +++ src/match.c | 5 ++++ src/player.c | 20 +++++++++---- src/weapons.c | 1 + 8 files changed, 117 insertions(+), 17 deletions(-) diff --git a/resources/example-configs/ktx/ktx.cfg b/resources/example-configs/ktx/ktx.cfg index 2a7feb01..6a24e43b 100644 --- a/resources/example-configs/ktx/ktx.cfg +++ b/resources/example-configs/ktx/ktx.cfg @@ -69,7 +69,7 @@ set k_ctf_rune_power_rgn 2.0 // regeneration rune power (default is 2 set k_ctf_rune_power_hst 2.0 // haste rune power (default is 2) // prewar -set k_prewar 1 // prewar setting (0 = prewar fire is disallowed, 1 = prewar fire is allowed, 2 = no fire or jump until ready) +set k_prewar 1 // prewar setting (0 = prewar fire is disallowed, 1 = prewar fire is allowed, 2 = no fire or jump until ready, 3 = prewar damage and frags) set k_sready 0 // players glow when not ready (0 = no, 1 = yes) set k_freeze 0 // freeze platforms and doors before matchstart (0 = no, 1 = yes) diff --git a/src/admin.c b/src/admin.c index 0d935a11..bdd1489a 100644 --- a/src/admin.c +++ b/src/admin.c @@ -790,22 +790,60 @@ void PlayersStopFire(void) } } +static void PlayersApplyPrewarLoadout(void) +{ + gedict_t *p; + + if (isRA()) + { + return; + } + + for (p = world; (p = find_plr(p));) + { + if (p && (p->ct == ctPlayer) && ISLIVE(p)) + { + p->s.v.health = 100; + p->s.v.max_health = max(p->s.v.max_health, p->s.v.health); + p->s.v.armortype = 0.8; + p->s.v.armorvalue = 200; + p->s.v.items = (((int)p->s.v.items) & ~(IT_ARMOR1 | IT_ARMOR2 | IT_ARMOR3)) | IT_ARMOR3; + } + } +} + void TogglePreWar(void) { - int k_prewar = bound(0, cvar("k_prewar"), 2); + int k_prewar = bound(0, cvar("k_prewar"), 3); if (!is_adm(self)) { return; } - if (++k_prewar > 2) + if (++k_prewar > 3) { k_prewar = 0; } switch (k_prewar) { + case 3: + if (match_in_progress != 2) + { + PlayersApplyPrewarLoadout(); + } + + if (!match_in_progress) + { + G_bprint(2, "Players may %s before match\n", redtext("damage and frag")); + } + else + { + G_sprint(self, 2, "Players may %s before match\n", redtext("damage and frag")); + } + break; + case 1: if (!match_in_progress) { diff --git a/src/client.c b/src/client.c index af704fe4..96af0a8b 100644 --- a/src/client.c +++ b/src/client.c @@ -1936,6 +1936,8 @@ void PutClientInServer(void) int items; int tele_flags; int i; + int k_prewar_mode = (int)cvar("k_prewar"); + qbool prewar_fight = ((match_in_progress != 2) && (k_prewar_mode == 3)); self->trackent = 0; @@ -1994,6 +1996,15 @@ void PutClientInServer(void) self->s.v.weapon = W_BestWeapon(); W_SetCurrentAmmo(); + if (prewar_fight && !isRA()) + { + self->s.v.health = 100; + self->s.v.max_health = max(self->s.v.max_health, self->s.v.health); + self->s.v.armortype = 0.8; + self->s.v.armorvalue = 200; + self->s.v.items = ((int)self->s.v.items) | IT_ARMOR3; + } + self->attack_finished = self->client_time; self->th_pain = player_pain; self->th_die = PlayerDie; @@ -4716,6 +4727,11 @@ void PlayerPostThink(void) self->client_predflags = PRDFL_FORCEOFF; else if ((match_in_progress == 1) || !can_prewar(true)) self->client_predflags = PRDFL_FORCEOFF; + // disable LG prediction in prewar when underwater to avoid weird shit + else if ((match_in_progress != 2) + && (self->s.v.weapon == IT_LIGHTNING) + && (self->s.v.waterlevel > 1)) + self->client_predflags = PRDFL_FORCEOFF; WeaponPrediction_MarkSendFlags(); // @@ -4727,8 +4743,11 @@ void PlayerPostThink(void) float velocity = sqrt( self->s.v.velocity[0] * self->s.v.velocity[0] + self->s.v.velocity[1] * self->s.v.velocity[1]); + int k_prewar_mode = (int)cvar("k_prewar"); + qbool prewar_fight = ((match_in_progress != 2) && (k_prewar_mode == 3)); - if (!match_in_progress && !match_over && !k_captains && !k_matchLess && !isHoonyModeAny()) + if (!match_in_progress && !prewar_fight && !match_over && !k_captains && !k_matchLess + && !isHoonyModeAny()) { if (iKey(self, "kf") & KF_SPEED) { @@ -5301,7 +5320,7 @@ void ClientObituary(gedict_t *targ, gedict_t *attacker) // Set it so it should update scores at next attempt. k_nochange = 0; - if (match_in_progress != 2) + if ((match_in_progress != 2) && ((int)cvar("k_prewar") != 3)) { return; // nothing TODO in non match } diff --git a/src/combat.c b/src/combat.c index 6c989ea3..9921b47a 100644 --- a/src/combat.c +++ b/src/combat.c @@ -454,6 +454,8 @@ void T_Damage(gedict_t *targ, gedict_t *inflictor, gedict_t *attacker, float dam char *attackerteam, *targteam, *attackername, *victimname; qbool tp4teamdmg = false; qbool isWipeout = cvar("k_clan_arena") == 2; + int k_prewar_mode = (int)cvar("k_prewar"); + qbool prewar_fight = ((match_in_progress != 2) && (k_prewar_mode == 3)); //midair and instagib float playerheight = 0, midheight = 0; @@ -472,8 +474,29 @@ void T_Damage(gedict_t *targ, gedict_t *inflictor, gedict_t *attacker, float dam return; } + // if k_prewar is 3, only take damage from other players + if (prewar_fight) + { + if (attacker->ct == ctPlayer) + { + // Don't damage self in prewar even if k_prewar is 3 + if (attacker == targ) + { + tp4teamdmg = true; + } + else if (targ->leavemealone) + { + return; + } + } + else + { + return; + } + } + // don't bounce around players in prewar who wish to be left alone - if (match_in_progress != 2 && targ->leavemealone) + if ((match_in_progress != 2) && !prewar_fight && targ->leavemealone) { if (attacker != targ && ((targ->ct == ctPlayer) && (attacker->ct == ctPlayer))) { @@ -671,7 +694,7 @@ void T_Damage(gedict_t *targ, gedict_t *inflictor, gedict_t *attacker, float dam dmg_dealt += save; - if (match_in_progress == 2) + if ((match_in_progress == 2) || prewar_fight) { targ->s.v.armorvalue = targ->s.v.armorvalue - save; } @@ -958,7 +981,7 @@ void T_Damage(gedict_t *targ, gedict_t *inflictor, gedict_t *attacker, float dam BotDamageInflictedEvent(attacker, targ); #endif - if ((match_in_progress == 2) && ((int)cvar("k_dmgfrags") || lgc_enabled())) + if ((match_in_progress == 2 || prewar_fight) && ((int)cvar("k_dmgfrags") || lgc_enabled())) { if ((attacker->ct == ctPlayer) && (targ->ct == ctPlayer) && (attacker != targ)) { @@ -976,7 +999,7 @@ void T_Damage(gedict_t *targ, gedict_t *inflictor, gedict_t *attacker, float dam // do the damage - if ((match_in_progress == 2) || (dtSUICIDE == targ->deathtype) // do suicide damage anyway + if ((match_in_progress == 2) || prewar_fight || (dtSUICIDE == targ->deathtype) // do suicide damage anyway || TELEDEATH(targ) || (k_practice && targ->ct != ctPlayer) // #practice mode# || (take >= 99999)) // do such huge damage even in prewar, prewar because indirectly here match_in_progress != 2 { @@ -1026,7 +1049,7 @@ void T_Damage(gedict_t *targ, gedict_t *inflictor, gedict_t *attacker, float dam } // show damage in sbar - if ((match_in_progress != 2) && ISLIVE(targ) && !k_matchLess) + if ((match_in_progress != 2) && !prewar_fight && ISLIVE(targ) && !k_matchLess) { if (!midair || ((int)targ->s.v.flags & FL_ONGROUND)) { @@ -1150,12 +1173,12 @@ void T_Damage(gedict_t *targ, gedict_t *inflictor, gedict_t *attacker, float dam } // mid air bonuses - if (midair && (match_in_progress == 2) && (attacker != targ) && take && rl_dmg) + if (midair && (match_in_progress == 2 || prewar_fight) && (attacker != targ) && take && rl_dmg) { MidairDamageBonus(attacker, targ, midheight); } - if (midair && (match_in_progress == 2) && stomp_dmg) + if (midair && (match_in_progress == 2 || prewar_fight) && stomp_dmg) { attacker->ps.mid_stomps++; targ->s.v.frags -= 3; diff --git a/src/commands.c b/src/commands.c index 18778cc8..53011242 100644 --- a/src/commands.c +++ b/src/commands.c @@ -2036,6 +2036,10 @@ void ModStatus2(void) switch ((int)cvar("k_prewar")) { + case 3: + ot = "players may damage and frag before match"; + break; + case 1: ot = "players may fire before match"; break; diff --git a/src/match.c b/src/match.c index 2e408458..0f883194 100644 --- a/src/match.c +++ b/src/match.c @@ -1314,6 +1314,11 @@ void StartMatch(void) SM_PrepareClients(); // put clients in server and reset some params + if ((int)cvar("k_prewar") == 3) + { + refresh_plus_scores(); + } + for (p = world; (p = find_client(p));) { p->socdDetectionCount = 0; diff --git a/src/player.c b/src/player.c index eb7fb28c..20c6efe8 100644 --- a/src/player.c +++ b/src/player.c @@ -760,6 +760,8 @@ void DeathBubbles(float num_bubbles); void PainSound(void) { int rs; + int k_prewar_mode = (int)cvar("k_prewar"); + qbool block_prewar_effects = (match_in_progress != 2) && (k_prewar_mode != 3); if (ISDEAD(self)) { @@ -772,7 +774,7 @@ void PainSound(void) { DeathBubbles(1); - if (match_in_progress != 2) + if (block_prewar_effects) { return; } @@ -792,7 +794,7 @@ void PainSound(void) if (self->s.v.watertype == CONTENT_SLIME) { // FIX ME put in some steam here - if (match_in_progress != 2) + if (block_prewar_effects) { return; } @@ -811,7 +813,7 @@ void PainSound(void) if (self->s.v.watertype == CONTENT_LAVA) { - if (match_in_progress != 2) + if (block_prewar_effects) { return; } @@ -987,11 +989,16 @@ void player_pain(struct gedict_s *attacker, float take) { // G_bprint(2, "player_pain\n"); - if (match_in_progress != 2) + if ((match_in_progress != 2) && ((int)cvar("k_prewar") != 3)) { return; // no pain at all in prewar } + if ((match_in_progress != 2) && ((int)cvar("k_prewar") == 3) && (self == attacker)) + { + return; // so self damage pain in prewar 3 + } + if (isCA() && (streq(getteam(self), getteam(attacker)) || self->no_pain)) { return; // No pain when shooting teammates in CA or when respawning (wipeout) @@ -1286,6 +1293,9 @@ void PlayerBreak(void); void PlayerDie(void) { + int k_prewar_mode = (int)cvar("k_prewar"); + qbool prewar_fight = ((match_in_progress != 2) && (k_prewar_mode == 3)); + self->ca_alive = false; if (!self->isBot && tot_mode_enabled() && cvar(FB_CVAR_BREAK_ON_DEATH)) @@ -1364,7 +1374,7 @@ void PlayerDie(void) return; } - if (match_in_progress == 2) + if ((match_in_progress == 2) || prewar_fight) { DeathSound(); } diff --git a/src/weapons.c b/src/weapons.c index 4985ed8d..58f779b0 100644 --- a/src/weapons.c +++ b/src/weapons.c @@ -3070,6 +3070,7 @@ qbool can_prewar(qbool fire) switch (k_prewar) { + case 3: case 1: goto captains; // probably u can fire/jump From 4d04c6e53ba305222559dd47c4dfb50f959cd696 Mon Sep 17 00:00:00 2001 From: ciscon Date: Sun, 19 Oct 2025 17:18:37 -0400 Subject: [PATCH 22/34] BUILD: support newer versions of gcc/clang by setting c standard to gnu17 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d8d31195..d21126ab 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -159,7 +159,7 @@ if (CMAKE_C_COMPILER_ID STREQUAL "MSVC") # 4459 - shadowing globals, broadly used target_compile_options(${PROJECT_NAME} PRIVATE /W4 /wd4100 /wd4210 /wd4456 /wd4459) else() - target_compile_options(${PROJECT_NAME} PRIVATE -Wall) + target_compile_options(${PROJECT_NAME} PRIVATE -Wall -std=gnu17) check_c_compiler_flag("-Wstrict-prototypes" HAS_CFLAG_STRICT_PROTOTYPES) if (HAS_CFLAG_STRICT_PROTOTYPES) From c43aafcdc31e66812bb9116c7eca4bc736b76376 Mon Sep 17 00:00:00 2001 From: Oscar Linderholm Date: Fri, 21 Nov 2025 16:08:39 +0100 Subject: [PATCH 23/34] Fix SOCD detection The SOCD detection counter was never incremented, resulting in SOCD detections never being reported. --- src/client.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/client.c b/src/client.c index c7c4e0ac..aea21d33 100644 --- a/src/client.c +++ b/src/client.c @@ -3710,6 +3710,8 @@ void PlayerPreThink(void) { int k_allow_socd_warning = cvar("k_allow_socd_warning"); + self->socdDetectionCount += 1; + if ((!match_in_progress) && (!self->isBot) && k_allow_socd_warning && (self->ct == ctPlayer) && (self->socdDetectionCount >= 3)) { G_bprint(PRINT_HIGH, From c871f3d2064e1881c694a7357986479b8cb96333 Mon Sep 17 00:00:00 2001 From: Oscar Linderholm Date: Fri, 4 Jul 2025 18:37:54 +0200 Subject: [PATCH 24/34] Add socd command The new command allows users to cycle between different SOCD detection modes: - Allow: Allow SOCD - Stats: Collect SOCD detection stats and print when the game ends - Warn: Display a warning when SOCD detection is triggered - Kick: Kick the player if SOCD detection is triggered --- include/g_consts.h | 5 +++++ src/client.c | 13 ++++++++++--- src/commands.c | 37 +++++++++++++++++++++++++++++++++++++ src/match.c | 7 +++++++ src/stats.c | 2 +- src/world.c | 2 +- 6 files changed, 61 insertions(+), 5 deletions(-) diff --git a/include/g_consts.h b/include/g_consts.h index 2db617c9..9ad1f821 100644 --- a/include/g_consts.h +++ b/include/g_consts.h @@ -338,3 +338,8 @@ enum #define MVDHIDDEN_DMGDONE_SPLASHDAMAGE (1 << 15) #define CLIENT_NAME_LEN 32 // Maximum client name, same value as in server. + +#define SOCD_ALLOW 0 +#define SOCD_STATS 1 +#define SOCD_WARN 2 +#define SOCD_KICK 3 diff --git a/src/client.c b/src/client.c index aea21d33..ebde85c2 100644 --- a/src/client.c +++ b/src/client.c @@ -3642,6 +3642,7 @@ void PlayerPreThink(void) { float r; qbool zeroFps = false; + int k_socd = cvar("k_socd"); if (self->k_timingWarnTime) { @@ -3708,16 +3709,22 @@ void PlayerPreThink(void) { if (self->fFramePerfectStrafeChangeCount / self->fStrafeChangeCount >= 0.75) { - int k_allow_socd_warning = cvar("k_allow_socd_warning"); - self->socdDetectionCount += 1; - if ((!match_in_progress) && (!self->isBot) && k_allow_socd_warning && (self->ct == ctPlayer) && (self->socdDetectionCount >= 3)) + if ((!match_in_progress) && (!self->isBot) && k_socd == SOCD_WARN && (self->ct == ctPlayer) && (self->socdDetectionCount >= 3)) { G_bprint(PRINT_HIGH, "[%s] Warning! %s: Movement assistance detected. Please disable iDrive or keyboard strafe assistance features.\n", SOCD_DETECTION_VERSION, self->netname); } + + if ((!self->isBot) && k_socd == SOCD_KICK && (self->ct == ctPlayer) && (self->socdDetectionCount >= 3)) + { + G_bprint(PRINT_HIGH, + "[%s] Kicked! %s: Movement assistance detected. Please disable iDrive or keyboard strafe assistance features.\n", + SOCD_DETECTION_VERSION, self->netname); + stuffcmd(self, "disconnect\n"); + } } self->socdValidationCount += 1; diff --git a/src/commands.c b/src/commands.c index 5517861c..45e28d4c 100644 --- a/src/commands.c +++ b/src/commands.c @@ -274,6 +274,7 @@ void giveme(void); static void dropitem(void); static void removeitem(void); static void dumpent(void); +static void socd(void); // } // { Frogbots @@ -660,6 +661,7 @@ const char CD_NODESC[] = "no desc"; #define CD_DROPITEM (CD_NODESC) // skip #define CD_REMOVEITEM (CD_NODESC) // skip #define CD_DUMPENT (CD_NODESC) // skip +#define CD_SOCD "cycle between SOCD detection modes" #define CD_VOTECOOP "vote for coop on/off" #define CD_COOPNMPU "new nightmare mode (pu drops) on/off" @@ -1035,6 +1037,7 @@ cmd_t cmds[] = { "dropitem", dropitem, 0, CF_BOTH | CF_PARAMS, CD_DROPITEM }, { "removeitem", removeitem, 0, CF_BOTH | CF_PARAMS, CD_REMOVEITEM }, { "dumpent", dumpent, 0, CF_BOTH | CF_PARAMS, CD_DUMPENT }, + { "socd", socd, 0, CF_PLAYER, CD_SOCD }, { "votecoop", votecoop, 0, CF_PLAYER | CF_MATCHLESS, CD_VOTECOOP }, { "coop_nm_pu", ToggleNewCoopNm, 0, CF_PLAYER | CF_MATCHLESS, CD_COOPNMPU }, { "demomark", DemoMark, 0, CF_BOTH, CD_DEMOMARK }, @@ -9348,6 +9351,40 @@ static void dumpent(void) G_sprint(self, 2, "Dumped %d entities\n", cnt); } +static void socd(void) +{ + int k_socd; + + if (match_in_progress) + { + return; + } + + k_socd = cvar("k_socd") + 1; + if (k_socd < SOCD_ALLOW || k_socd > SOCD_KICK) + { + k_socd = SOCD_ALLOW; + } + + switch (k_socd) + { + case SOCD_ALLOW: + G_bprint(2, "%s: allow\n", redtext("SOCD")); + break; + case SOCD_STATS: + G_bprint(2, "%s: stats after game\n", redtext("SOCD")); + break; + case SOCD_WARN: + G_bprint(2, "%s: warn on violation\n", redtext("SOCD")); + break; + case SOCD_KICK: + G_bprint(2, "%s: kick on violation\n", redtext("SOCD")); + break; + } + + cvar_set("k_socd", va("%d", (int)k_socd)); +} + qbool lgc_enabled(void) { return cvar(LGCMODE_VARIABLE) != 0; diff --git a/src/match.c b/src/match.c index 09863dd4..f7d2c946 100644 --- a/src/match.c +++ b/src/match.c @@ -1411,6 +1411,7 @@ void PrintCountdown(int seconds) char *ot = ""; char *nowp = ""; char *matchtag = redtext(ezinfokey(world, "matchtag")); + int k_socd = cvar("k_socd"); strlcat(text, va("%s: %2s\n\n\n", redtext("Countdown"), dig3(seconds)), sizeof(text)); @@ -1651,6 +1652,12 @@ void PrintCountdown(int seconds) strlcat(text, va("%s %4s\n", "Powerups", redtext(Get_PowerupsStr())), sizeof(text)); } + strlcat(text, va("%s %6s\n", SOCD_DETECTION_VERSION, + k_socd == SOCD_ALLOW ? redtext("allow") + : k_socd == SOCD_STATS ? redtext("stats") + : k_socd == SOCD_WARN ? redtext("warn") + : redtext("kick")), sizeof(text)); + if (cvar("k_dmgfrags")) { strlcat(text, va("%s %4s\n", "Dmgfrags", redtext("on")), sizeof(text)); diff --git a/src/stats.c b/src/stats.c index ac043368..43f24033 100644 --- a/src/stats.c +++ b/src/stats.c @@ -764,7 +764,7 @@ void OnePlayerStats(gedict_t *p, int tp) } // movement - if (!p->isBot) + if (!p->isBot && cvar("k_socd") >= SOCD_STATS) { G_bprint(2, "%s: %s:%.1f%% (%d/%d) %s:%d/%d%s [%s]\n", redtext("Movement"), redtext("Perfect strafes"), p->matchStrafeChangeCount > 0 ? 100.0 * p->matchPerfectStrafeCount / p->matchStrafeChangeCount : 0.0, diff --git a/src/world.c b/src/world.c index ed79994d..4f9dff14 100644 --- a/src/world.c +++ b/src/world.c @@ -1007,7 +1007,7 @@ void FirstFrame(void) RegisterCvar("k_teamoverlay"); // q3 like team overlay - RegisterCvar("k_allow_socd_warning"); // socd + RegisterCvarEx("k_socd", "1"); // { SP RegisterCvarEx("k_monster_spawn_time", "20"); From fe7f774aaad08733391485f41fd271afc473dd95 Mon Sep 17 00:00:00 2001 From: Oscar Linderholm Date: Tue, 25 Nov 2025 17:27:06 +0100 Subject: [PATCH 25/34] Add item pickup bonus for ToT mode This introduces a new mode when playing the ToT mode that aims to help you practice item timings. When picking up any of the following items, you will receive an additional 100 health: - lg - rl - mega - rockets --- include/fb_globals.h | 28 +++++++++-------- src/bot_commands.c | 27 +++++++++++++++- src/items.c | 50 +++++++++++++++++++++-------- src/match.c | 75 ++++++++++++++++++++++++++++++++++++++------ src/world.c | 1 + 5 files changed, 144 insertions(+), 37 deletions(-) diff --git a/include/fb_globals.h b/include/fb_globals.h index 29138172..4a87dc5a 100644 --- a/include/fb_globals.h +++ b/include/fb_globals.h @@ -367,6 +367,7 @@ int FrogbotSkillLevel(void); int FrogbotHealth(void); int FrogbotWeapon(void); int FrogbotQuadMultiplier(void); +qbool FrogbotItemPickupBonus(void); // botthink.qc void SetMarker(gedict_t *client, gedict_t *marker); @@ -393,19 +394,20 @@ void RunRandomTrials(float min, float max, float mult); // editor qbool HasSavedMarker(void); -#define FB_CVAR_ENABLED "k_fb_enabled" -#define FB_CVAR_OPTIONS "k_fb_options" -#define FB_CVAR_AUTOADD_LIMIT "k_fb_autoadd_limit" -#define FB_CVAR_AUTOREMOVE_AT "k_fb_autoremove_at" -#define FB_CVAR_AUTO_DELAY "k_fb_auto_delay" -#define FB_CVAR_SKILL "k_fb_skill" -#define FB_CVAR_DEBUG "k_fb_debug" -#define FB_CVAR_ADMIN_ONLY "k_fb_admin_only" -#define FB_CVAR_FREEZE_PREWAR "k_fb_freeze_prewar" -#define FB_CVAR_HEALTH "k_fb_health" -#define FB_CVAR_WEAPON "k_fb_weapon" -#define FB_CVAR_BREAK_ON_DEATH "k_fb_break_on_death" -#define FB_CVAR_QUAD_MULTIPLIER "k_fb_quad_multiplier" +#define FB_CVAR_ENABLED "k_fb_enabled" +#define FB_CVAR_OPTIONS "k_fb_options" +#define FB_CVAR_AUTOADD_LIMIT "k_fb_autoadd_limit" +#define FB_CVAR_AUTOREMOVE_AT "k_fb_autoremove_at" +#define FB_CVAR_AUTO_DELAY "k_fb_auto_delay" +#define FB_CVAR_SKILL "k_fb_skill" +#define FB_CVAR_DEBUG "k_fb_debug" +#define FB_CVAR_ADMIN_ONLY "k_fb_admin_only" +#define FB_CVAR_FREEZE_PREWAR "k_fb_freeze_prewar" +#define FB_CVAR_HEALTH "k_fb_health" +#define FB_CVAR_WEAPON "k_fb_weapon" +#define FB_CVAR_BREAK_ON_DEATH "k_fb_break_on_death" +#define FB_CVAR_QUAD_MULTIPLIER "k_fb_quad_multiplier" +#define FB_CVAR_ITEM_PICKUP_BONUS "k_fb_item_pickup_bonus" void BotsFireLogic(void); diff --git a/src/bot_commands.c b/src/bot_commands.c index 6e268ad2..ff16453c 100644 --- a/src/bot_commands.c +++ b/src/bot_commands.c @@ -130,6 +130,11 @@ int FrogbotQuadMultiplier(void) return (int)cvar(FB_CVAR_QUAD_MULTIPLIER); } +qbool FrogbotItemPickupBonus(void) +{ + return tot_mode_enabled() && (qbool)cvar(FB_CVAR_ITEM_PICKUP_BONUS); +} + static team_t* AddTeamToList(int *teamsFound, char *team, int topColor, int bottomColor) { int i; @@ -2263,6 +2268,25 @@ static void FrogbotsSetQuadMultiplier(void) } } +static void FrogbotsSetItemPickupBonus(void) +{ + if (!bots_enabled()) + { + G_sprint(self, 2, "Bots are disabled by the server.\n"); + return; + } + + if (!tot_mode_enabled()) + { + G_sprint(self, 2, "This is option is only available in ToT mode.\n"); + return; + } + + cvar_fset(FB_CVAR_ITEM_PICKUP_BONUS, !cvar(FB_CVAR_ITEM_PICKUP_BONUS)); + G_sprint(self, 2, "item pickup bonus changed to %s\n", + (int)cvar(FB_CVAR_ITEM_PICKUP_BONUS) ? redtext("on") : redtext("off")); +} + typedef struct frogbot_cmd_s { char *name; @@ -2283,7 +2307,8 @@ static frogbot_cmd_t std_commands[] = { "weapon", FrogbotsSetWeapon, "Set which weapon the bot should use" }, { "breakondeath", FrogbotsSetBreakOnDeath, "Automatically break when you die" }, { "togglequad", FrogbotsToggleQuad, "Toggle quad damage" }, - { "quadmultiplier", FrogbotsSetQuadMultiplier, "Set quad damage multiplier" }}; + { "quadmultiplier", FrogbotsSetQuadMultiplier, "Set quad damage multiplier" }, + { "itempickupbonus", FrogbotsSetItemPickupBonus, "Toggle item pickup bonus" }}; static frogbot_cmd_t editor_commands[] = { diff --git a/src/items.c b/src/items.c index f938772f..9bcec75c 100644 --- a/src/items.c +++ b/src/items.c @@ -196,7 +196,11 @@ float T_Heal(gedict_t *e, float healamount, float ignore) e->s.v.health = other->s.v.max_health; } - if (e->s.v.health > 250) + if (FrogbotItemPickupBonus() && e->s.v.health > 300) + { + e->s.v.health = 300; + } + else if (e->s.v.health > 250) { e->s.v.health = 250; } @@ -301,12 +305,12 @@ void health_touch(void) if (self->healtype == 2) // Megahealth? Ignore max_health... { - if (other->s.v.health >= 250) + if (other->s.v.health >= 250 && !FrogbotItemPickupBonus()) { return; } - if (!T_Heal(other, self->healamount, 1)) + if (!T_Heal(other, FrogbotItemPickupBonus() ? 100 : self->healamount, 1)) { return; } @@ -348,7 +352,7 @@ void health_touch(void) if (self->healtype == 2) { other->s.v.items = (int)other->s.v.items | IT_SUPERHEALTH; - if (deathmatch != 4) + if (deathmatch != 4 || (deathmatch == 4 && FrogbotItemPickupBonus())) { self->s.v.nextthink = g_globalvars.time + 5; self->think = (func_t) item_megahealth_rot; @@ -378,7 +382,7 @@ void item_megahealth_rot(void) { other = PROG_TO_EDICT(self->s.v.owner); - if (other->s.v.health > other->s.v.max_health) + if (other->s.v.health > other->s.v.max_health && !FrogbotItemPickupBonus()) { if (!(other->ctf_flag & CTF_RUNE_RGN)) { @@ -630,22 +634,22 @@ void bound_other_ammo(void) { if (other->s.v.ammo_shells > 100) { - other->s.v.ammo_shells = 100; + other->s.v.ammo_shells = FrogbotItemPickupBonus() ? 255 : 100; } if (other->s.v.ammo_nails > 200) { - other->s.v.ammo_nails = 200; + other->s.v.ammo_nails = FrogbotItemPickupBonus() ? 255 : 200; } if (other->s.v.ammo_rockets > 100) { - other->s.v.ammo_rockets = 100; + other->s.v.ammo_rockets = FrogbotItemPickupBonus() ? 255 : 100; } if (other->s.v.ammo_cells > 100) { - other->s.v.ammo_cells = 100; + other->s.v.ammo_cells = FrogbotItemPickupBonus() ? 255 : 100; } } float RankForWeapon(float w) @@ -964,6 +968,16 @@ void weapon_touch(void) G_Error("weapon_touch: unknown classname"); } + if (FrogbotItemPickupBonus() && ( + !strcmp(self->classname, "weapon_rocketlauncher") || + !strcmp(self->classname, "weapon_lightning"))) + { + if (!T_Heal(other, 100, 1)) + { + return; + } + } + TookWeaponHandler(other, new, false); mi_print(other, new, va("%s got %s", getname(other), self->netname)); @@ -1227,13 +1241,23 @@ void ammo_touch(void) } else if (weapon == 3) // rockets { - if (other->s.v.ammo_rockets >= 100) + if (FrogbotItemPickupBonus()) { - return; + if (!T_Heal(other, 100, 1)) + { + return; + } } + else + { + if (other->s.v.ammo_rockets >= 100) + { + return; + } - real_ammo = other->s.v.ammo_rockets; - other->s.v.ammo_rockets += ammo; + real_ammo = other->s.v.ammo_rockets; + other->s.v.ammo_rockets += ammo; + } } else if (weapon == 4) // cells { diff --git a/src/match.c b/src/match.c index f7d2c946..47dac3a6 100644 --- a/src/match.c +++ b/src/match.c @@ -864,22 +864,74 @@ void SM_PrepareMap(void) if (deathmatch >= 4) { - if (streq(p->classname, "weapon_nailgun") || streq(p->classname, "weapon_supernailgun") - || streq(p->classname, "weapon_supershotgun") - || streq(p->classname, "weapon_rocketlauncher") - || streq(p->classname, "weapon_grenadelauncher") - || streq(p->classname, "weapon_lightning")) - { // no weapons for any of this deathmatches (4 or 5) + int disallowed_weapons = (int)cvar("k_disallow_weapons") & DA_WPNS; + + // no weapons for any of this deathmatches (4 or 5), + // unless ToT mode with item pickup bonus is enabled and + // the weapon isn't disallowed. + if (streq(p->classname, "weapon_nailgun")) + { + soft_ent_remove(p); + continue; + } + else if (streq(p->classname, "weapon_supernailgun")) + { + soft_ent_remove(p); + continue; + } + else if (streq(p->classname, "weapon_supershotgun")) + { + soft_ent_remove(p); + continue; + } + else if (streq(p->classname, "weapon_grenadelauncher")) + { + soft_ent_remove(p); + continue; + } + else if (streq(p->classname, "weapon_rocketlauncher") && + (!FrogbotItemPickupBonus() || + (disallowed_weapons & IT_ROCKET_LAUNCHER))) + { + soft_ent_remove(p); + continue; + } + else if (streq(p->classname, "weapon_lightning") && + (!FrogbotItemPickupBonus() || + (disallowed_weapons & IT_LIGHTNING))) + { soft_ent_remove(p); continue; } if (deathmatch == 4) { - if (streq(p->classname, "item_shells") || streq(p->classname, "item_spikes") - || streq(p->classname, "item_rockets") || streq(p->classname, "item_cells") - || (streq(p->classname, "item_health") && ((int)p->s.v.spawnflags & H_MEGA))) - { // no weapon ammo and megahealth for dmm4 + // no weapon ammo and megahealth for dmm4 + if (streq(p->classname, "item_shells")) + { + soft_ent_remove(p); + continue; + } + else if (streq(p->classname, "item_spikes")) + { + soft_ent_remove(p); + continue; + } + else if (streq(p->classname, "item_rockets") && + !FrogbotItemPickupBonus()) + { + soft_ent_remove(p); + continue; + } + else if (streq(p->classname, "item_cells")) + { + soft_ent_remove(p); + continue; + } + else if ((streq(p->classname, "item_health") && + ((int)p->s.v.spawnflags & H_MEGA)) && + !FrogbotItemPickupBonus()) + { soft_ent_remove(p); continue; } @@ -1710,6 +1762,9 @@ void PrintCountdown(int seconds) strlcat(text, va("Bot health %15s\n", dig3(FrogbotHealth())), sizeof(text)); strlcat(text, va("Bot skill %16s\n", dig3(FrogbotSkillLevel())), sizeof(text)); strlcat(text, va("Quad damage multiplier %3s\n", dig3(FrogbotQuadMultiplier())), sizeof(text)); + strlcat(text, va("Item Pickup Bonus %8s\n", + redtext(FrogbotItemPickupBonus() ? "on": "off")), sizeof(text)); + } if (matchtag[0]) diff --git a/src/world.c b/src/world.c index 4f9dff14..5036e7cf 100644 --- a/src/world.c +++ b/src/world.c @@ -1057,6 +1057,7 @@ void FirstFrame(void) RegisterCvarEx(FB_CVAR_WEAPON, "2"); RegisterCvarEx(FB_CVAR_BREAK_ON_DEATH, "1"); RegisterCvarEx(FB_CVAR_QUAD_MULTIPLIER, "4"); + RegisterCvarEx(FB_CVAR_ITEM_PICKUP_BONUS, "0"); for (i = 0; i < MAX_CLIENTS; i++) { From 2dd9dbc73da70c4d3f3137182f9183fc6e5e59cc Mon Sep 17 00:00:00 2001 From: Daniel Svensson Date: Tue, 25 Nov 2025 18:15:23 +0100 Subject: [PATCH 26/34] DOWNLOAD: Align chunksperframe to server default. --- resources/example-configs/ktx/mvdsv.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/example-configs/ktx/mvdsv.cfg b/resources/example-configs/ktx/mvdsv.cfg index 606cfbe7..c6705c28 100644 --- a/resources/example-configs/ktx/mvdsv.cfg +++ b/resources/example-configs/ktx/mvdsv.cfg @@ -65,7 +65,7 @@ sv_demoExtraNames 0 // show player names in demo filenames ( sv_demotxt 2 // create demo .txt (0 = off, 1 = on, 2 = json) sv_demodir demos // demos directory name sv_maxdownloadrate 100000 // maximum download client rate -sv_downloadchunksperframe 4 // increase chunked download speed rate (1=77kB/s, 4=308kB/s) +sv_downloadchunksperframe 30 // increase chunked download speed rate (1=77kB/s, 4=308kB/s) sv_onrecordfinish mvdfinish // name.qws will be started after demo recording is finished sv_demoMaxDirSize 262144 // maximum demos dir size. 4096000=4GB sv_demoClearOld 10 // if total demos size > sv_demoMaxDirSize, this will delete x demos From a489de7b312e0595c34f22e23c9fc240d7fcefd7 Mon Sep 17 00:00:00 2001 From: Oscar Linderholm Date: Wed, 26 Nov 2025 16:22:09 +0100 Subject: [PATCH 27/34] Add spawnicide When spawnicide is enabled, players can no longer walk onto spawn points without being killed. Deaths caused by spawnicide also subtract a frag. There are three spawnicide modes: - Disabled: default - Prewar: only triggers during prewar - Match: also enabled during a match --- include/deathtype.h | 1 + include/g_local.h | 8 +++ include/progs.h | 1 + src/client.c | 25 ++++++++- src/commands.c | 45 ++++++++++++++++ src/items.c | 127 +++++++++++++++++++++++++++++++++++++++++++- src/match.c | 19 +++++++ src/triggers.c | 1 + src/world.c | 6 +++ 9 files changed, 231 insertions(+), 2 deletions(-) diff --git a/include/deathtype.h b/include/deathtype.h index 31229f24..79508fbe 100644 --- a/include/deathtype.h +++ b/include/deathtype.h @@ -19,6 +19,7 @@ DEATHTYPE( dtSTOMP, stomp ) DEATHTYPE( dtTELE1, tele1 ) DEATHTYPE( dtTELE2, tele2 ) DEATHTYPE( dtTELE3, tele3 ) +DEATHTYPE( dtTELE4, tele4 ) DEATHTYPE( dtEXPLO_BOX, explo_box ) DEATHTYPE( dtLASER, laser ) DEATHTYPE( dtFIREBALL, fireball ) diff --git a/include/g_local.h b/include/g_local.h index bcd5038d..5a7f9db9 100644 --- a/include/g_local.h +++ b/include/g_local.h @@ -1254,3 +1254,11 @@ extern int maxPlayerCount; #define AUTOTRACK_POWERUPS_PREDICT_TIME 2 qbool AllowMonster(gedict_t *e); + +#define SPAWNICIDE_DISABLED 0 +#define SPAWNICIDE_PREWAR 1 +#define SPAWNICIDE_MATCH 2 + +int SpawnicideStatus(void); +void SpawnicideEnable(void); +void SpawnicideDisable(void); diff --git a/include/progs.h b/include/progs.h index 19a7da92..df13bd9d 100644 --- a/include/progs.h +++ b/include/progs.h @@ -1220,6 +1220,7 @@ typedef struct gedict_s // { // let mvdsv know when player has teleported, and adjust for high-ping int teleported; + float teleport_time; // } // { diff --git a/src/client.c b/src/client.c index ebde85c2..807fa2f1 100644 --- a/src/client.c +++ b/src/client.c @@ -5174,8 +5174,31 @@ void ClientObituary(gedict_t *targ, gedict_t *attacker) return; } -// } + // can only occur if k_spawnicide is enabled + if (dtTELE4 == targ->deathtype) + { + switch ((int)(g_random() * 3)) + { + case 0: + G_bprint(PRINT_MEDIUM, + "%s couldn't resist the shiny spawn point\n", victimname); + break; + case 1: + G_bprint(PRINT_MEDIUM, + "%s got too close to the baby factory\n", victimname); + break; + default: + G_bprint(PRINT_MEDIUM, + "%s was fragged by poor life choices\n", victimname); + break; + } + + targ->s.v.frags -= 1; + logfrag(targ, targ); + return; + } +// } if (attacker->ct == ctPlayer) // so, inside this "if" targ and attacker is players { if (targ == attacker) diff --git a/src/commands.c b/src/commands.c index 45e28d4c..7dcc403d 100644 --- a/src/commands.c +++ b/src/commands.c @@ -130,6 +130,7 @@ void ToggleQPoint(void); */ void ToggleRespawns(void); void ToggleSpawnPoints(void); +void ToggleSpawnicide(void); void ToggleBerzerk(void); void ToggleSpecTalk(void); void ToggleSpeed(void); @@ -352,6 +353,7 @@ const char CD_NODESC[] = "no desc"; #define CD_WHOVOTE "info on received votes" #define CD_SPAWN "toggle spawn modes" #define CD_SPAWNPOINTS "toggle visible spawn points" +#define CD_SPAWNICIDE "toggle spawnicide" #define CD_POWERUPS "quad, \230\230\230, ring & suit" #define CD_PUPICKUP "change powerups pickup policy" #define CD_ANTILAG "toggle antilag" @@ -716,6 +718,7 @@ cmd_t cmds[] = { "whovote", ModStatusVote, 0, CF_BOTH | CF_MATCHLESS, CD_WHOVOTE }, { "spawn", ToggleRespawns, 0, CF_PLAYER | CF_SPC_ADMIN, CD_SPAWN }, { "spawn_show", ToggleSpawnPoints, 0, CF_PLAYER | CF_SPC_ADMIN, CD_SPAWNPOINTS }, + { "spawnicide", ToggleSpawnicide, 0, CF_PLAYER | CF_SPC_ADMIN, CD_SPAWNICIDE }, { "powerups", TogglePowerups, 0, CF_PLAYER | CF_SPC_ADMIN | CF_PARAMS, CD_POWERUPS }, { "powerups_pickup", TogglePuPickup, 0, CF_PLAYER | CF_SPC_ADMIN | CF_PARAMS, CD_PUPICKUP }, { "antilag", antilag, 0, CF_PLAYER | CF_SPC_ADMIN, CD_ANTILAG }, @@ -2702,6 +2705,48 @@ void ToggleSpawnPoints(void) } } +void ToggleSpawnicide(void) +{ + int spawnicide = cvar("k_spawnicide"); + + if (match_in_progress) + { + return; + } + + spawnicide++; + if (spawnicide > SPAWNICIDE_MATCH) + { + spawnicide = SPAWNICIDE_DISABLED; + } + + cvar_set("k_spawnicide", va("%d", spawnicide)); + + // We are using the show spawn point code to display teleporter exit + // spawns as well, so to trigger it we need to reset it. + if (cvar("k_spm_show")) + { + HideSpawnPoints(); + ShowSpawnPoints(); + } + + SpawnicideDisable(); + + switch (spawnicide) + { + case SPAWNICIDE_DISABLED: + G_sprint(self, 2, "Spawnicide %s\n", redtext("off")); + break; + case SPAWNICIDE_PREWAR: + SpawnicideEnable(); + G_sprint(self, 2, "Spawnicide %s\n", redtext("prewar")); + break; + case SPAWNICIDE_MATCH: + G_sprint(self, 2, "Spawnicide %s\n", redtext("match")); + break; + } +} + void TogglePowerups(void) { char arg[64]; diff --git a/src/items.c b/src/items.c index 9bcec75c..d7014a76 100644 --- a/src/items.c +++ b/src/items.c @@ -2966,7 +2966,7 @@ gedict_t* Spawn_OnePoint(gedict_t *spawn_point, vec3_t org, int effects) void Spawn_SpawnPoints(char *classname, int effects) { - gedict_t *e; + gedict_t *e, *s; vec3_t org; for (e = world; (e = ez_find(e, classname));) @@ -2981,6 +2981,32 @@ void Spawn_SpawnPoints(char *classname, int effects) Spawn_OnePoint(e, org, effects); } + + if (SpawnicideStatus()) + { + for (e = world; (e = ez_find(e, "trigger_teleport"));) + { + if (e->targetname) + { + continue; + } + + if (!(s = find(world, FOFS(targetname), e->target))) + { + continue; + } + + VectorCopy(s->s.v.origin, org); + org[2] += 0; + + if (isHoonyModeDuel()) + { + effects = (e->hoony_nomination ? (EF_GREEN | EF_RED) : 0); + } + + Spawn_OnePoint(s, org, effects); + } + } } void ShowSpawnPoints(void) @@ -3009,3 +3035,102 @@ void HideSpawnPoints(void) } } +int SpawnicideStatus(void) +{ + return (int)cvar("k_spawnicide"); +} + +static void SpawnicideTouch(void) +{ + gedict_t *p; + + for (p = world; (p = find_plr(p));) + { + if (p->isBot) + { + continue; + } + + if (g_globalvars.time - p->spawn_time < 1) + { + continue; + } + + if (g_globalvars.time - p->teleport_time < 1) + { + continue; + } + + if ((self->s.v.absmin[0] > p->s.v.absmax[0]) || (self->s.v.absmin[1] > p->s.v.absmax[1]) + || (self->s.v.absmin[2] > p->s.v.absmax[2]) + || (self->s.v.absmax[0] < p->s.v.absmin[0]) + || (self->s.v.absmax[1] < p->s.v.absmin[1]) + || (self->s.v.absmax[2] < p->s.v.absmin[2])) + { + continue; + } + + if (ISLIVE(p)) + { + p->deathtype = dtTELE4; + T_Damage(p, p, p, 50000); + } + } +} + +static void SpawnicideCreate(gedict_t *spawn_point, vec3_t org) +{ + gedict_t *p = spawn(); + + p->s.v.solid = SOLID_TRIGGER; + p->s.v.movetype = MOVETYPE_NONE; + p->touch = (func_t)SpawnicideTouch; + p->netname = "Spawnicide"; + p->classname = "spawnicide"; + + setsize(p, -16, -16, -24, 16, 16, 32); + setorigin(p, PASSVEC3(org)); + VectorCopy(spawn_point->s.v.angles, p->s.v.angles); + trap_makevectors(p->s.v.angles); +} + +void SpawnicideEnable(void) +{ + gedict_t *e, *s; + vec3_t org; + + for (e = world; (e = ez_find(e, "info_player_deathmatch"));) + { + VectorCopy(e->s.v.origin, org); + org[2] += 0; + SpawnicideCreate(e, org); + } + + for (e = world; (e = ez_find(e, "trigger_teleport"));) + { + if (e->targetname) + { + continue; + } + + if (!(s = find(world, FOFS(targetname), e->target))) + { + continue; + } + + VectorCopy(s->s.v.origin, org); + org[2] += 0; + SpawnicideCreate(e, org); + } +} + +void SpawnicideDisable(void) +{ + gedict_t *e; + + for (e = world; (e = ez_find(e, "spawnicide"));) + { + ent_remove(e); + } +} + diff --git a/src/match.c b/src/match.c index 47dac3a6..03710f8b 100644 --- a/src/match.c +++ b/src/match.c @@ -478,6 +478,11 @@ void EndMatch(float skip_log) { g_matchstarttime = 0; } + + if (SpawnicideStatus() == SPAWNICIDE_MATCH) + { + SpawnicideDisable(); + } } void SaveOvertimeStats(void) @@ -1236,6 +1241,15 @@ void StartMatch(void) HideSpawnPoints(); + if (SpawnicideStatus() == SPAWNICIDE_MATCH) + { + SpawnicideEnable(); + } + else + { + SpawnicideDisable(); + } + match_start_time = g_globalvars.time; g_matchstarttime = (int)(g_globalvars.time * 1000); match_in_progress = 2; @@ -1704,6 +1718,11 @@ void PrintCountdown(int seconds) strlcat(text, va("%s %4s\n", "Powerups", redtext(Get_PowerupsStr())), sizeof(text)); } + if (SpawnicideStatus() == SPAWNICIDE_MATCH) + { + strlcat(text, va("Spawnicide %s\n", redtext("on")), sizeof(text)); + } + strlcat(text, va("%s %6s\n", SOCD_DETECTION_VERSION, k_socd == SOCD_ALLOW ? redtext("allow") : k_socd == SOCD_STATS ? redtext("stats") diff --git a/src/triggers.c b/src/triggers.c index 17348f7a..e14128a1 100644 --- a/src/triggers.c +++ b/src/triggers.c @@ -756,6 +756,7 @@ void teleport_touch(void) } other->teleported = 1; + other->teleport_time = g_globalvars.time; teleport_player(other, t->s.v.origin, t->mangle, TFLAGS_FOG_SRC | TFLAGS_FOG_DST | TFLAGS_SND_SRC | TFLAGS_SND_DST | TFLAGS_VELOCITY_ADJUST); diff --git a/src/world.c b/src/world.c index 5036e7cf..7ca2f71d 100644 --- a/src/world.c +++ b/src/world.c @@ -696,6 +696,11 @@ void Customize_Maps(void) } } + if (SpawnicideStatus() == SPAWNICIDE_PREWAR) + { + SpawnicideEnable(); + } + if (cvar("k_spm_show")) { ShowSpawnPoints(); @@ -848,6 +853,7 @@ void FirstFrame(void) RegisterCvar("k_overtime"); RegisterCvar("k_exttime"); RegisterCvar("k_spw"); + RegisterCvar("k_spawnicide"); RegisterCvar("k_lockmin"); RegisterCvar("k_lockmax"); RegisterCvar("k_spectalk"); From a5ab0515cd94960fcb7f0131e982145ba2a8e7df Mon Sep 17 00:00:00 2001 From: Oscar Linderholm Date: Sat, 29 Nov 2025 18:13:16 +0100 Subject: [PATCH 28/34] Display matchtag when player goes ready --- src/match.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/match.c b/src/match.c index 03710f8b..23453a07 100644 --- a/src/match.c +++ b/src/match.c @@ -2869,8 +2869,9 @@ void PlayerReady(qbool startIdlebot) if (!isHoonyModeAny() || (HM_current_point() == 0)) { - G_bprint(2, "%s %s%s\n", self->netname, redtext("is ready"), - ((isTeam() || isCTF()) ? va(" \220%s\221", getteam(self)) : "")); + G_bprint(2, "%s %s%s%s\n", self->netname, redtext("is ready"), + ((isTeam() || isCTF()) ? va(" \220%s\221", getteam(self)) : ""), + (matchtag[0] ? va(" - %s", matchtag) : " - no matchtag set")); } nready = CountRPlayers(); From c30a56349087a1e9f7a558dd869276e9332251d5 Mon Sep 17 00:00:00 2001 From: Oscar Linderholm Date: Sun, 30 Nov 2025 17:15:54 +0100 Subject: [PATCH 29/34] Make bot skill mode toggleable This change makes the adjustments introduced in the following commit configurable by the server admin and also toggleable in-game: https://github.com/QW-Group/ktx/commit/55497e87822af62a7fe34575254c30ec2a052f6f The changes that made the bot easier interfered with competitive bot challenges (endif, ToT mode, and regular povdmm4), where players had become accustomed to the more difficult bots. However, since these changes were merged in April, I decided to keep the easier mode as the default, but allow server admins to configure the default mode by setting k_fb_easy_skill_mode. Players can also toggle the setting in-game by running: botcmd easyskillmode. The selected skill mode is displayed during countdown. --- include/fb_globals.h | 2 ++ src/bot_botimp.c | 20 ++++++++++---------- src/bot_commands.c | 21 ++++++++++++++++++++- src/match.c | 6 ++++++ src/world.c | 1 + 5 files changed, 39 insertions(+), 11 deletions(-) diff --git a/include/fb_globals.h b/include/fb_globals.h index 4a87dc5a..eeecdbb4 100644 --- a/include/fb_globals.h +++ b/include/fb_globals.h @@ -368,6 +368,7 @@ int FrogbotHealth(void); int FrogbotWeapon(void); int FrogbotQuadMultiplier(void); qbool FrogbotItemPickupBonus(void); +qbool FrogbotEasySkillMode(void); // botthink.qc void SetMarker(gedict_t *client, gedict_t *marker); @@ -408,6 +409,7 @@ qbool HasSavedMarker(void); #define FB_CVAR_BREAK_ON_DEATH "k_fb_break_on_death" #define FB_CVAR_QUAD_MULTIPLIER "k_fb_quad_multiplier" #define FB_CVAR_ITEM_PICKUP_BONUS "k_fb_item_pickup_bonus" +#define FB_CVAR_EASY_SKILL_MODE "k_fb_easy_skill_mode" void BotsFireLogic(void); diff --git a/src/bot_botimp.c b/src/bot_botimp.c index 12065b81..bd6205b8 100644 --- a/src/bot_botimp.c +++ b/src/bot_botimp.c @@ -153,11 +153,7 @@ void RegisterSkillVariables(void) RegisterCvar(FB_CVAR_OPPONENT_MIDAIR_VOLATILITY_INCREASE); } -void setLgcModeSkillAttributes(int skill, int aimskill) { - // Keep LGC bot skill attributes separate so we can change - // general skill attributes without affecting LGC mode, so players - // can still play LGC mode on same terms as old records. - +void setSkillAttributes(int skill, int aimskill) { // Old frogbot settings (items generally) cvar_fset(FB_CVAR_ACCURACY, 45 - min(skill, 10) * 2.25); cvar_fset(FB_CVAR_DODGEFACTOR, RangeOverSkill(skill, 0.0f, 1.0f)); @@ -208,7 +204,7 @@ void setLgcModeSkillAttributes(int skill, int aimskill) { cvar_fset(FB_CVAR_MISSILEDODGE_TIME, RangeOverSkill(skill, 1.0f, 0.5f)); } -void setSkillAttributes(int skill, int aimskill) { +void setSkillAttributesEasySkillMode(int skill, int aimskill) { // Old frogbot settings (items generally) cvar_fset(FB_CVAR_ACCURACY, 45 - min(skill, 10) * 2.25); cvar_fset(FB_CVAR_DODGEFACTOR, RangeOverSkill(skill, 0.0f, 1.0f)); @@ -269,10 +265,14 @@ qbool SetAttributesBasedOnSkill(int skill) skill = bound(MIN_FROGBOT_SKILL, skill, MAX_FROGBOT_SKILL); aimskill = bound(MIN_FROGBOT_SKILL, skill, MAX_FROGBOT_AIM_SKILL); - if (lgc_enabled()) { - G_bprint(2, "LGC mode enabled - using legacy bot skill attributes.\n"); - setLgcModeSkillAttributes(skill, aimskill); - } else { + if (FrogbotEasySkillMode()) + { + G_bprint(2, "%s\n", redtext("Using easy bot skill mode")); + setSkillAttributesEasySkillMode(skill, aimskill); + } + else + { + G_bprint(2, "%s\n", redtext("Using default bot skill mode")); setSkillAttributes(skill, aimskill); } diff --git a/src/bot_commands.c b/src/bot_commands.c index ff16453c..892bcae8 100644 --- a/src/bot_commands.c +++ b/src/bot_commands.c @@ -135,6 +135,11 @@ qbool FrogbotItemPickupBonus(void) return tot_mode_enabled() && (qbool)cvar(FB_CVAR_ITEM_PICKUP_BONUS); } +qbool FrogbotEasySkillMode(void) +{ + return (qbool)cvar(FB_CVAR_EASY_SKILL_MODE); +} + static team_t* AddTeamToList(int *teamsFound, char *team, int topColor, int bottomColor) { int i; @@ -2287,6 +2292,19 @@ static void FrogbotsSetItemPickupBonus(void) (int)cvar(FB_CVAR_ITEM_PICKUP_BONUS) ? redtext("on") : redtext("off")); } +static void FrogbotsSetEasySkillMode(void) +{ + if (!bots_enabled()) + { + G_sprint(self, 2, "Bots are disabled by the server.\n"); + return; + } + + cvar_fset(FB_CVAR_EASY_SKILL_MODE, !cvar(FB_CVAR_EASY_SKILL_MODE)); + G_sprint(self, 2, "easy skill mode changed to %s\n", + (int)cvar(FB_CVAR_EASY_SKILL_MODE) ? redtext("on") : redtext("off")); +} + typedef struct frogbot_cmd_s { char *name; @@ -2308,7 +2326,8 @@ static frogbot_cmd_t std_commands[] = { "breakondeath", FrogbotsSetBreakOnDeath, "Automatically break when you die" }, { "togglequad", FrogbotsToggleQuad, "Toggle quad damage" }, { "quadmultiplier", FrogbotsSetQuadMultiplier, "Set quad damage multiplier" }, - { "itempickupbonus", FrogbotsSetItemPickupBonus, "Toggle item pickup bonus" }}; + { "itempickupbonus", FrogbotsSetItemPickupBonus, "Toggle item pickup bonus" }, + { "easyskillmode", FrogbotsSetEasySkillMode, "Toggle easy skill mode" }}; static frogbot_cmd_t editor_commands[] = { diff --git a/src/match.c b/src/match.c index 23453a07..5420e5ea 100644 --- a/src/match.c +++ b/src/match.c @@ -1786,6 +1786,12 @@ void PrintCountdown(int seconds) } + if (CountBots() >= 1) + { + strlcat(text, va("\nBot Skill Mode %s\n", + redtext(FrogbotEasySkillMode() ? "easy" : "default")), sizeof(text)); + } + if (matchtag[0]) { strlcat(text, va("\nmatchtag %s\n\n\n", matchtag), sizeof(text)); diff --git a/src/world.c b/src/world.c index 7ca2f71d..59034840 100644 --- a/src/world.c +++ b/src/world.c @@ -1064,6 +1064,7 @@ void FirstFrame(void) RegisterCvarEx(FB_CVAR_BREAK_ON_DEATH, "1"); RegisterCvarEx(FB_CVAR_QUAD_MULTIPLIER, "4"); RegisterCvarEx(FB_CVAR_ITEM_PICKUP_BONUS, "0"); + RegisterCvarEx(FB_CVAR_EASY_SKILL_MODE, "1"); for (i = 0; i < MAX_CLIENTS; i++) { From a8734282f53777e31c8ce0a34a77e9c9a51bcf5b Mon Sep 17 00:00:00 2001 From: Oscar Linderholm Date: Sun, 30 Nov 2025 19:55:38 +0100 Subject: [PATCH 30/34] Allow pause without matchtag if k_pause_without_matchtag is set Previously, players could only pause if a matchtag was set. This change adds support for the cvar k_pause_without_matchtag. When enabled, the check for matchtag is skipped, and players can use their available pause requests regardless of whether the game has a matchtag. --- src/client.c | 6 +++--- src/world.c | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/client.c b/src/client.c index 807fa2f1..fe9645c3 100644 --- a/src/client.c +++ b/src/client.c @@ -5734,10 +5734,10 @@ qbool PlayerCanPause(gedict_t *p) qbool playerCanPause = false; char *matchtag = ezinfokey(world, "matchtag"); - // Check for matchtag. If it is set, it is an official (probably), so pause might be allowed. - if ((NULL != matchtag) && matchtag[0]) + // Check for matchtag, OR allow if k_pause_without_matchtag is set. + if (cvar("k_pause_without_matchtag") || ((matchtag != NULL) && matchtag[0])) { - // matchtag is found. Let's see if the player can still pause. + // Let's see if the player can still pause. if (p->k_pauseRequests > 0) { p->k_pauseRequests--; diff --git a/src/world.c b/src/world.c index 59034840..300271dd 100644 --- a/src/world.c +++ b/src/world.c @@ -785,6 +785,7 @@ void FirstFrame(void) RegisterCvar("_k_nospecs"); // internal usage, will reject spectators connection RegisterCvar("k_noitems"); + RegisterCvarEx("k_pause_without_matchtag", "0"); RegisterCvar("k_random_maplist"); // select random map from k_ml_XXX variables. From 10aded977563535d32beff7f269cb96ffd8d844e Mon Sep 17 00:00:00 2001 From: Oscar Linderholm Date: Mon, 1 Dec 2025 16:45:31 +0100 Subject: [PATCH 31/34] Allow spawn markers to be shown during games k_spm_show can now be set to 2, which makes spawn markers render even after the match has started. The variable can also be cycled by running the spawn_show command as a connected client. --- include/g_local.h | 5 +++++ src/commands.c | 30 +++++++++++++++++++++++++----- src/hoonymode.c | 2 +- src/match.c | 5 ++++- src/race.c | 2 +- src/world.c | 2 +- 6 files changed, 37 insertions(+), 9 deletions(-) diff --git a/include/g_local.h b/include/g_local.h index 5a7f9db9..e8c814e8 100644 --- a/include/g_local.h +++ b/include/g_local.h @@ -1255,10 +1255,15 @@ extern int maxPlayerCount; qbool AllowMonster(gedict_t *e); +#define SPAWN_SHOW_DISABLED 0 +#define SPAWN_SHOW_PREWAR 1 +#define SPAWN_SHOW_MATCH 2 + #define SPAWNICIDE_DISABLED 0 #define SPAWNICIDE_PREWAR 1 #define SPAWNICIDE_MATCH 2 +int SpawnShowStatus(void); int SpawnicideStatus(void); void SpawnicideEnable(void); void SpawnicideDisable(void); diff --git a/src/commands.c b/src/commands.c index 7dcc403d..e9734a73 100644 --- a/src/commands.c +++ b/src/commands.c @@ -2686,22 +2686,42 @@ void ToggleRespawns(void) G_bprint(2, "%s\n", respawn_model_name(k_spw)); } +int SpawnShowStatus(void) +{ + return (int)cvar("k_spm_show"); +} + void ToggleSpawnPoints(void) { + int spawn_show = cvar("k_spm_show"); + if (match_in_progress) { return; } - cvar_toggle_msg(self, "k_spm_show", redtext("visible spawn points")); + spawn_show++; - if (cvar("k_spm_show")) + if (spawn_show > SPAWN_SHOW_MATCH) { - ShowSpawnPoints(); + spawn_show = SPAWN_SHOW_DISABLED; } - else + + cvar_set("k_spm_show", va("%d", spawn_show)); + switch (spawn_show) { - HideSpawnPoints(); + case SPAWNICIDE_DISABLED: + HideSpawnPoints(); + G_sprint(self, 2, "Visible spawns %s\n", redtext("off")); + break; + case SPAWNICIDE_PREWAR: + ShowSpawnPoints(); + G_sprint(self, 2, "Visible spawns %s\n", redtext("prewar")); + break; + case SPAWNICIDE_MATCH: + ShowSpawnPoints(); + G_sprint(self, 2, "Visible spawns %s\n", redtext("match")); + break; } } diff --git a/src/hoonymode.c b/src/hoonymode.c index ccab3e3e..ac35d989 100644 --- a/src/hoonymode.c +++ b/src/hoonymode.c @@ -855,7 +855,7 @@ static void HM_deselect_spawn(gedict_t *spawn) } // If showing all spawns, just remove the glow. otherwise remove the marker. - if (cvar("k_spm_show")) + if (SpawnShowStatus() > SPAWN_SHOW_DISABLED) { spawn->wizard->s.v.effects = (int)spawn->wizard->s.v.effects & ~effects; } diff --git a/src/match.c b/src/match.c index 5420e5ea..e482a34e 100644 --- a/src/match.c +++ b/src/match.c @@ -1239,7 +1239,10 @@ void StartMatch(void) SM_PrepareMap(); // remove/add some items from map regardind with dmm and game mode - HideSpawnPoints(); + if (SpawnShowStatus() != SPAWN_SHOW_MATCH) + { + HideSpawnPoints(); + } if (SpawnicideStatus() == SPAWNICIDE_MATCH) { diff --git a/src/race.c b/src/race.c index dd7ffb0e..228adda5 100644 --- a/src/race.c +++ b/src/race.c @@ -529,7 +529,7 @@ void race_shutdown(char *msg) race_cancel(true, "%s", msg); race_remove_ent(); race_unready_all(); - if (cvar("k_spm_show")) + if (SpawnShowStatus() > SPAWN_SHOW_DISABLED) { ShowSpawnPoints(); } diff --git a/src/world.c b/src/world.c index 300271dd..6edd3533 100644 --- a/src/world.c +++ b/src/world.c @@ -701,7 +701,7 @@ void Customize_Maps(void) SpawnicideEnable(); } - if (cvar("k_spm_show")) + if (SpawnShowStatus() > SPAWN_SHOW_DISABLED) { ShowSpawnPoints(); } From c166537fafc128cdcbe6f1d126d8089461a812bb Mon Sep 17 00:00:00 2001 From: Oscar Linderholm Date: Sun, 7 Dec 2025 10:33:21 +0100 Subject: [PATCH 32/34] Fix format string --- src/commands.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands.c b/src/commands.c index e9734a73..96b6d48b 100644 --- a/src/commands.c +++ b/src/commands.c @@ -5425,7 +5425,7 @@ void latejoin(void) } // Store the requested team for later use - snprintf(self->ljteam, sizeof(self->ljteam), arg_2); + snprintf(self->ljteam, sizeof(self->ljteam), "%s", arg_2); //self->ljteam = arg_2; // Start the election From 18ce9990e07f08f433759d68f47115e93fa05067 Mon Sep 17 00:00:00 2001 From: Oscar Linderholm Date: Sat, 13 Dec 2025 19:20:28 +0100 Subject: [PATCH 33/34] Revert "LEAVEMEALONE: players can't bother you in prewar" This reverts commit 483edaedc79017d7aaaee86f7bfb759bf622012d. --- include/progs.h | 1 - src/client.c | 14 ++------------ src/combat.c | 15 --------------- src/commands.c | 30 ------------------------------ src/match.c | 1 - src/triggers.c | 2 +- src/weapons.c | 23 ----------------------- 7 files changed, 3 insertions(+), 83 deletions(-) diff --git a/include/progs.h b/include/progs.h index df13bd9d..1f4812f6 100644 --- a/include/progs.h +++ b/include/progs.h @@ -968,7 +968,6 @@ typedef struct gedict_s int nullStrafeCount; // SOCD - qbool leavemealone; float shownick_time; // used to force centerprint is off at desired time clientType_t ct; // client type for client edicts // { timing diff --git a/src/client.c b/src/client.c index fe9645c3..07549203 100644 --- a/src/client.c +++ b/src/client.c @@ -1806,7 +1806,7 @@ void PutClientInServer(void) self->classname = "player"; self->s.v.health = 100; self->s.v.takedamage = DAMAGE_AIM; - self->s.v.solid = isCA() ? SOLID_NOT : self->leavemealone ? SOLID_TRIGGER : SOLID_SLIDEBOX; + self->s.v.solid = isCA() ? SOLID_NOT : SOLID_SLIDEBOX; self->s.v.movetype = MOVETYPE_WALK; self->show_hostile = 0; self->s.v.max_health = 100; @@ -2029,7 +2029,7 @@ void PutClientInServer(void) } else { - self->s.v.solid = self->leavemealone ? SOLID_TRIGGER : SOLID_SLIDEBOX; + self->s.v.solid = SOLID_SLIDEBOX; } setorigin(self, PASSVEC3(self->s.v.origin)); @@ -3873,16 +3873,6 @@ void PlayerPreThink(void) race_player_pre_think(); - if (self->leavemealone) - { - if ((self->s.v.mins[0] == 0) || (self->s.v.mins[1] == 0)) - { - // This can happen if the world 'squashes' a SOLID_NOT entity, mvdsv will turn into corpse - setsize(self, PASSVEC3(VEC_HULL_MIN), PASSVEC3(VEC_HULL_MAX)); - } - setorigin(self, PASSVEC3(self->s.v.origin)); - } - // brokenankle included here if (self->s.v.button2 || self->brokenankle) { diff --git a/src/combat.c b/src/combat.c index b02178af..b73176e1 100644 --- a/src/combat.c +++ b/src/combat.c @@ -463,21 +463,6 @@ void T_Damage(gedict_t *targ, gedict_t *inflictor, gedict_t *attacker, float dam return; } - // don't bounce around players in prewar who wish to be left alone - if (match_in_progress != 2 && targ->leavemealone) - { - if (attacker != targ && ((targ->ct == ctPlayer) && (attacker->ct == ctPlayer))) - { - return; - } - else if (dtTELE1 == targ->deathtype // always do tele damage - || dtTELE2 == targ->deathtype // always do tele damage - || dtTELE3 == targ->deathtype) // always do tele damage - { - // telefrags still work, to avoid getting stuck - } - } - // can't damage other players in race if (isRACE() && (attacker != targ)) { diff --git a/src/commands.c b/src/commands.c index 96b6d48b..bdbdc2ab 100644 --- a/src/commands.c +++ b/src/commands.c @@ -72,7 +72,6 @@ void CTFBasedSpawn(void); // } CTF void FragsDown(void); void FragsUp(void); -void LeaveMeAlone(void); void ListWhoNot(void); void ModStatus1(void); void ModStatus2(void); @@ -395,7 +394,6 @@ const char CD_NODESC[] = "no desc"; #define CD_CTOCT "Show octal charset table" #define CD_CTHEX "Show hexadecimal charset table" #define CD_SHOWNICK "pointed player's info" -#define CD_LEAVEMEALONE "can't shoot/bounce players in prewar" #define CD_TIME5 "set timelimit to 5 mins" #define CD_TIME10 "set timelimit to 10 mins" #define CD_TIME15 "set timelimit to 15 mins" @@ -762,7 +760,6 @@ cmd_t cmds[] = { "sct_hex", ShowCharsetTableHexa, 0, CF_BOTH, CD_CTHEX }, { "about", ShowVersion, 0, CF_BOTH | CF_MATCHLESS, CD_ABOUT }, { "shownick", ShowNick, 0, CF_PLAYER | CF_PARAMS, CD_SHOWNICK }, - { "leavemealone", LeaveMeAlone, 0, CF_PLAYER | CF_PARAMS, CD_LEAVEMEALONE }, { "time5", DEF(TimeSet), 5.0f, CF_PLAYER | CF_SPC_ADMIN, CD_TIME5 }, { "time10", DEF(TimeSet), 10.0f, CF_PLAYER | CF_SPC_ADMIN, CD_TIME10 }, { "time15", DEF(TimeSet), 15.0f, CF_PLAYER | CF_SPC_ADMIN, CD_TIME15 }, @@ -4141,33 +4138,6 @@ void ShowNick(void) self->shownick_time = g_globalvars.time + 0.8; // clear centerprint at this time } -void LeaveMeAlone(void) -{ - if (match_in_progress) - { - return; - } - - if (isRA() || isRACE()) - { - return; - } - - if (self->leavemealone) - { - G_bprint(2, "%s %s\n", self->netname, redtext("no longer wants to be left alone")); - self->s.v.solid = SOLID_SLIDEBOX; - } - else - { - G_bprint(2, "%s %s\n", self->netname, redtext("wants to be left alone")); - self->s.v.solid = SOLID_TRIGGER; - } - - setorigin(self, PASSVEC3(self->s.v.origin)); - self->leavemealone = !self->leavemealone; -} - // qqshka // below predefined settings for usermodes diff --git a/src/match.c b/src/match.c index e482a34e..38dbebe8 100644 --- a/src/match.c +++ b/src/match.c @@ -985,7 +985,6 @@ static void SM_PrepareClients(void) for (p = world; (p = find_plr(p));) { players[player_count++] = p; - p->leavemealone = false; // can't have this enabled during match } for (i = player_count - 1; i > 0; i--) diff --git a/src/triggers.c b/src/triggers.c index e14128a1..81f5cfd3 100644 --- a/src/triggers.c +++ b/src/triggers.c @@ -715,7 +715,7 @@ void teleport_touch(void) } // only teleport living creatures - if (ISDEAD(other) || (!isRACE() && (other->s.v.solid != SOLID_SLIDEBOX) && !other->leavemealone)) + if (ISDEAD(other) || (!isRACE() && (other->s.v.solid != SOLID_SLIDEBOX))) { return; } diff --git a/src/weapons.c b/src/weapons.c index 287cc28b..95e116ae 100644 --- a/src/weapons.c +++ b/src/weapons.c @@ -377,12 +377,6 @@ void TraceAttack(float damage, vec3_t dir, qbool send_effects) return; } - //can't touch/damage players who want to be left alone - if (PROG_TO_EDICT(g_globalvars.trace_ent)->ct == ctPlayer && PROG_TO_EDICT(g_globalvars.trace_ent)->leavemealone) - { - return; - } - if (PROG_TO_EDICT(g_globalvars.trace_ent)->s.v.takedamage) { if (PROG_TO_EDICT(g_globalvars.trace_ent)->ct == ctPlayer) @@ -966,11 +960,6 @@ void T_MissileTouch(void) return; } - if (other->leavemealone) - { - return; - } - if (self->voided) { return; @@ -1334,12 +1323,6 @@ void GrenadeTouch(void) return; } - // can't touch players who want to be left alone - if (other->leavemealone) - { - return; - } - if (other->s.v.takedamage) { if (other->ct == ctPlayer) @@ -1534,12 +1517,6 @@ void spike_touch(void) return; } - // can't touch players who want to be left alone - if (other->leavemealone) - { - return; - } - if (self->voided) { return; From 8cadd8ad29b33246132b8bf255ae4e9a882586c0 Mon Sep 17 00:00:00 2001 From: Oscar Linderholm Date: Sat, 13 Dec 2025 19:20:34 +0100 Subject: [PATCH 34/34] Revert "BUG FIX: relink after player solid state changes" This reverts commit eb35c93023d0a0991ec4b66666ceca2f7f60c30c. --- src/client.c | 7 +------ src/match.c | 6 ------ 2 files changed, 1 insertion(+), 12 deletions(-) diff --git a/src/client.c b/src/client.c index 07549203..4f4acb58 100644 --- a/src/client.c +++ b/src/client.c @@ -170,11 +170,9 @@ void CheckTiming(void) p->s.v.solid = 0; p->s.v.movetype = 0; SetVector(p->s.v.velocity, 0, 0, 0); // speed is zeroed and not restored - - // Relink after solid change to avoid stale area list membership - setorigin(p, PASSVEC3(p->s.v.origin)); } } + } else { @@ -3056,9 +3054,6 @@ void BackFromLag(void) self->s.v.takedamage = self->k_timingTakedmg; self->s.v.solid = self->k_timingSolid; self->s.v.movetype = self->k_timingMovetype; - - // Relink after solid change to ensure proper area list placement - setorigin(self, PASSVEC3(self->s.v.origin)); } } diff --git a/src/match.c b/src/match.c index 38dbebe8..5ce59415 100644 --- a/src/match.c +++ b/src/match.c @@ -1998,9 +1998,6 @@ void standby_think(void) p->s.v.movetype = 0; p->s.v.modelindex = 0; p->model = ""; - - // Relink after solid change to keep area lists consistent - setorigin(p, PASSVEC3(p->s.v.origin)); } } } @@ -2532,9 +2529,6 @@ void StopTimer(int removeDemo) p->s.v.solid = SOLID_SLIDEBOX; p->s.v.movetype = MOVETYPE_WALK; setmodel(p, "progs/player.mdl"); - - // Relink after solid change so players are returned to the correct list - setorigin(p, PASSVEC3(p->s.v.origin)); } }